2013-08-21 5 views
1

문제 정의 :멀티 스레드 임베디드 리눅스 어플리케이션 상태 머신 디자인

우리는 Linux를 실행하는 산업용 임베디드 시스템 용 애플리케이션을 설계하고 있습니다.

시스템은 외부 세계의 이벤트에 의해 구동됩니다. 시스템에 대한 입력은 다음과 같을 수있다 : (즉 스톱 같은 프로세서의 GPIO로 연결 ) 디지털 IO 라인 형태의 시스템에

  1. 몇 입력한다.
  2. 시스템은 웹 브라우저를 통해 시스템을 제어 할 수있는 웹 서버를 실행합니다.
  3. 시스템이 TCP 서버를 실행합니다. 모든 PC 또는 HMI 디바이스는 TCP/IP를 통해 명령을 보낼 수 있습니다.

시스템은 Modbus를 사용하여 UART를 통해 RS485 슬레이브 장치를 구동하거나 제어해야합니다. 시스템은 또한 Cooler ON/OFF 등과 같이 거의 IO 라인을 제어 할 필요가 없습니다. 우리는 상태 시스템이이 어플리케이션을 정의하는 데 필수적이라고 믿습니다. 핵심 응용 프로그램은 RS485 노예를 제어 할 수있는 다음 스레드를 가진다 멀티 스레드 응용 프로그램 ...

  1. 메인 스레드
  2. 스레드를해야한다.
  3. 웹 인터페이스에서 이벤트를 처리하는 스레드.
  4. 디지털 I/O 이벤트를 처리하는 스레드.
  5. 스레드 우리는 P 스레드 상태 신호를 & 대기를 사용하는 TCP/IP (소켓) 스레드 간 통신

통해 명령을 처리한다. 초기 설계 접근법 (메인 쓰레드에서 하나의 상태 머신)에 따라, 시스템 (웹 또는 TCP/IP 또는 디지털 I/O)에 대한 모든 입력 이벤트는 메인 쓰레드로 릴레이되어야하며, 해당 쓰레드와 통신해야한다. 그 사건은 예정되어있다. 전형적인 시나리오는 웹 인터페이스를 통해 RS485 슬레이브의 상태를 얻는 것입니다. 이 경우, 웹 인터페이스 스레드는 이벤트를 주 스레드로 중계해야하며 주 스레드는 상태를 변경 한 다음 해당 제어 장치가 RS485 슬레이브 &이 응답하는 스레드에 이벤트를 전달합니다. 메인 쓰레드는 응답을 웹 인터페이스 쓰레드로 되돌려 보내야한다.

질문 :

  1. 각 스레드가함으로써 메인 쓰레드의 복잡성을 줄여 자신의 상태 머신을해야 하는가? 그런 경우에도 주 스레드에 상태 시스템을 보유하려면 여전히 이 필요합니까?
  2. 모든 스레드 처리 입력 이벤트는 주 스레드를 우회하는 이벤트를 처리하는 스레드로 직접 통신 할 수 있습니까? 예를 들어 웹 인터페이스 스레드는 RS485 슬레이브를 제어하는 ​​스레드와 직접 통신 할 수 있습니까?
  3. pthread 조건 신호를 사용하는 것이 좋습니다 & 스레드 간 통신을 기다리거나 더 나은 방법이 있습니까?
  4. 외부에서 이벤트가 하나의 스레드에서 대기 할 수있는 방법 & 다른 스레드에서 응답 하시겠습니까? 예 :웹 인터페이스 스레드는 일반적으로 웹 서버 CGI 저장소의 프로세스 간 통신 인 프로세스 간 통신을위한 POSIX 메시지 대기열의 이벤트에 대해 을 대기합니다. CGI bin은이 메시지 큐를 통해 웹 인터페이스 스레드에 이벤트를 보냅니다. 이 이벤트를 처리 할 때 웹 인터페이스 스레드는 다른 스레드의 응답을 기다립니다. 이 경우 이전 이벤트 처리를 완료하고 POSIX 메시지 대기열에서 다시 대기 상태가 될 때까지 웹 인터페이스의 새 이벤트를 처리 할 수 ​​없습니다.

너무 큰 설명을 드려 죄송합니다 ... 다른 사람들이 이해하고 도와 줄 수있는 최선의 방법으로 설명을 드렸기를 바랍니다.

필요한 경우 더 많은 입력을 제공 할 수 있습니다.

+1

원본 질문에 설명 된 접근법이 활성 객체 (액터) 디자인 패턴을 다시 고안 한 것처럼 보입니다. 나는 오픈 소스 QP 활성 객체 프레임 워크 (http://www.state-machine.com/qp)를 살펴볼 것을 권한다. http://www.state-machine.com/linux에는 p-threads가있는 POSIX에이 프레임 워크의 포트가 있습니다. –

+0

물론 Mr.Miro, 나는 그 옵션을 살펴볼 것이다 ... 덕분에 톤 – hprasath

답변

3

항상 이러한 요구 사항을 수행하려고하는 것은 주 스레드가 될 수있는 하나의 'SM'스레드로 실행되는 하나의 상태 시스템을 사용하는 것입니다. 이 스레드는 'EventQueue'입력 producer-cosumer 대기열에서 시간 초과로 대기합니다. 타임 아웃은 필요한 경우 상태 머신에 타임 아웃 이벤트를 제공 할 수있는 내부 델타 큐를 실행하는 데 사용됩니다.

다른 모든 스레드는 메시지를 EventQueue로 푸시하여 상태 엔진에 이벤트를 전달하고 SM 스레드는이를 직렬 방식으로 처리합니다.

SM의 작업 루틴이 무언가를해야한다고 결정하면 동 기적으로 아무것도 기다리지 않아야하므로 스레드/susbsystem이 그것을 수행 할 수있는 입력 대기열로 요청 메시지를 밀어서 작업을 요청해야합니다.

내 메시지 클래스에는 대개 '명령'열거 형, '결과'열거 형, 데이터 버퍼 포인터 (대량 데이터를 전송해야하는 경우), 오류 - 메시지 포인터 (에러가 없다면 null), 그리고 어떤 종류의 요청이라도 비동기 큐잉을 허용하고 (성공 또는 실패 여부와 상관없이) 완전한 결과를 리턴하는 데 필요한만큼의 다른 상태.

악의적 인 교착 상태, 통제되지 않은 통신 및 반복 할 수없는 undebuggable 상호 작용의 세계로 들어 가지 않고도 유연하고 확장 가능한 방식으로 이러한 메시지 전달, 하나의 SM 디자인 만이 가능하다는 것을 발견했습니다.

디자인에 대해 묻는 첫 번째 질문은 '이상한 문제가 있으면 시스템을 어떻게 디버깅 할 수 있습니까?'입니다. 위의 디자인에서 바로 대답 할 수 있습니다. 'SM 스레드에서 대기열에있는 모든 이벤트를 기록합니다. 모든 이벤트가 순차적으로 발생하므로 항상 어떤 동작이 취해 졌는지 항상 알 수 있습니다.' 다른 디자인이 제안되면, 위의 질문을하고, 좋은 대답이 곧 나오지 않는다면 결코 작동하지 않을 것입니다.

그래서 :

  1. 스레드 또는 스레드 서브 시스템, 고급, OK, 자신의 내부 기능을 수행하기 위해 별도의 상태 기계를 사용 할 수 있습니다. 이 SM은 시스템의 나머지 부분에서 보이지 않아야합니다.

  2. NO!

  3. 는 생산자 - 소비자 차단 큐를 구현하기는 pthread 조건 신호를 & 대기를 사용합니다.

  4. 스레드/서브 시스템 당 하나의 입력 대기열. 모든 입력은 메시지 형태로이 대기열로 이동합니다. 각 메시지의 명령/상태는 메시지를 식별하고 메시지를 처리해야합니다.BTW

, 나는 100 %는 C에서이 작업을 수행 할 것 ++ 샷건으로 헤드 :

+0

+1 디버깅. 통찰력있는 분해. – andy256

+0

Mr.Martin James, 내가 언급 한 모든 점을 고려해 보겠습니다. 나는 새로운 디자인으로 당신에게 몇 가지 일을하고 나서 다시해야 할 것입니다. 감사합니다 .. – hprasath

+0

@ 마틴 제임스, 나는 당신의 설계 접근 방식에 몇 가지 설명이 있습니다. 주 상태 기계 또는 주 스레드가 비동기 적으로 서브 시스템 스레드로 입력 이벤트를 보내려는 경우, 주 스레드가 주 스레드로 결과를 얻는 방법 입력 이벤트를 기다리는 것이 바쁠 것입니다. 또한 언급 한 내부 델타 큐에 대해 이해할 수 없습니까? 그것에 대해 자세히 설명해 주시겠습니까? – hprasath

0

내가 원래 클론 지멘스 ES122C 터미널 (EC115EC270)을 위해 작성된 레거시 포함 된 라이브러리를 구현하지 않는 한 제어 장치. 이 라이브러리 및 OS에는 사용자가 설명하는 내용이 다소 포함되어 있습니다. 원래의 하드웨어는 80186 cpu를 기반으로했습니다. 운영체제, 지멘스 용 RMOS, FXMOS (Google에 게시되지 않았 음)는 기본 컨트롤러 작업에 필요한 모든 것을 갖추고있었습니다. 선점 형 멀티 태스킹, 태스크 간 통신, 세마포어, 타이머 및 I/O 이벤트가 있었지만 메모리 보호는 없었습니다. 그 물건을 RaspberryPi (예 : Linux)에 이식했습니다.

우리는 메모리 보호 기능이 없기 때문에 pthread를 사용하여 레거시 "작업"을 시뮬레이션하므로 스레드는 의미 상으로 가장 가깝습니다. 나머지 구현에서는 epoll API를 사용합니다. 이것은 이벤트를 생성하는 모든 것을 의미합니다. 사건은 무언가가 일어나고, 타이머가 만료되고, 다른 스레드가 데이터를 보내고, TCP 소켓이 연결되고, IO 핀이 상태를 변경 한 경우 등입니다. 이렇게하려면 모든 이벤트 소스가 파일 설명자로 변환되어야합니다. 리눅스는 정확히 다음과 같은 몇 가지 syscall을 제공합니다 : task to task comm을위한 고전 유닉스 파이프를 사용했습니다. 타이머 이벤트 용 timerfd API를 사용했습니다. TCP 통신을위한 정상적인 소켓을 사용했습니다. 은 직렬 I/O를 위해 간단한 장치로 올바른 장치 /dev/???이 작동합니다. 필자의 경우에는 신호가 필요하지 않지만 Linux는 필요한 경우 'signalfd'를 제공합니다.

다음 나는 원래의 의미를 시뮬레이트하기 위해 포장 된 epoll_wait입니다.

나는 매력처럼 작동합니다. TL

, DR

은 당신이 아마 필요하지 epoll 파일의 API에 깊은 봐.

EDIT : 예, 마틴 제임스의 조언은 특히 훌륭합니다. 4. 각 스레드는 epoll_wait를 통해 이벤트를 대기하는 루프에 있어야합니다.