아두이노에 쓰레드가 필요할 때 Arduino Multi-Threading Library
참조 : http://www.kwartzlab.ca/2010/09/arduino-multi-threading-librar/
불행인지 다행인지 모르겠지만 아두이노는 쓰레드를 지원하지 않습니다. 오로지 하나의 쓰레드가 setup() 이후 loop() 무한반복을 할 뿐입니다. (인터럽트 서비스와 타이머는 논외로 칩시다!)
어찌보면 복잡한 관리가 필요없어서 단순하게 순차적인 프로그래밍을 하면 되는 환경이지만, 병렬로 처리해야 하는 부분이 생기면 좀 답답해지기도 합니다. 특히 통신 인터페이스를 통해 데이터 송수신을 하는 경우 thread 생각이 간절해 집니다. timer 가 있긴하지만.. 이걸로는 부족하죠.
그리고 당연하게도(?) 이런 생각을 한 유저들 중 누군가가 라이브러리를 만들었습니다. Multi-threading library 입니다.
대단히 유용한 라이브러리이지만 일반적으로 사용하던 thread와는 사용방법이 좀 틀립니다.
1. 이 라이브러리를 사용하는 아두이노 스케치는 loop() 함수를 구현하지 않는다.
왜냐면 thread 관리를 위해 라이브러리 쪽에서 구현해 쓰기 때문입니다. 명시적으로 loop() 함수를 만들 필요가 없습니다. 대신에 Thread 를 상속하는 클래스를 생성 후 그 안에 loop() 멤버 함수를 구현해서 사용하면 됩니다. Thread 의 loop() 멤버함수는 boolean 리턴값을 가집니다. 이 값이 true 일 경우는 loop() 함수가 계속 실행되지만 false 일 경우 Thread 가 종료됩니다.
2. ThreadList Object
Thread 인스턴스를 생성한 후에는 ThreadList 에 반드시 등록해주어야 합니다. add_thread() 를 함수를 통해 등록할 수 있습니다. Thread 의 동작이 종료된 경우 자동으로 Thread object는 리스트에서 제거됩니다.
3. Tiered ThreadLists
An interesting thing about ThreadLists is that they are Threads in and of themselves. That way a tiered system can be crated where a lower-priority ThreadList object can be placed inside of a higher one. That way, the higher-priority ThreadList will call one loop() from each of the high-priority Threads, and then a loop() from the first Thread in the lower-priority list. It will then call the loop() function in all of the high-priority Threads again, and then the next one from the low-priority list… and so on.
4. Kill()
Thread 종료 방법은 두 가지가 있습니다. 인스턴스 내부에 있는 kill_flag 를 true로 설정하는 방법과 kill(true)를 호출하는 방법입니다.
어떤 경우든 thread 안에서 절대 delete 키워드를 사용해서는 안됩니다. 메모리 충돌이 발생합니다.
5. 라이브러리의 한계
Multi-thread 라고는 하나, 루틴을 쪼개서 여러개를 돌리는 형태이기 때문에 어느 한 쓰레드에서 멈추면 전체 시스템이 같이 멈추게 됩니다. 따라서 delay() 함수를 사용해서는 아니됩니다. 대신에 라이브러리에서 제공하는 sleep(), sleep_milli(), sleep_micro() 함수를 사용해야 합니다. 이 함수를 사용하면 Thread 내부의 loop() 루틴이 지정한 시간이 지날때까지 실행되지 않을 것입니다.
6. 소스코드
라이브러리는 GitHub 에서 받으 실 수 있습니다. 문서는 여기에서 받으세요.
백문이 불여일견 예제 코드 보시면 사용방법이 좀 더 쉽게 눈에 들어올 것입니다.
// -*- mode: c++ -*- // Arduino-Compatible Multi-Threading Library (mthread) // Copyright (C) 2010-2012 Jonathan Lamothe <jonathan@jlamothe.net> // This program is free software: you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // You should have received a copy of the GNU Lesser General Public // License along with this program. If not, see // <http://www.gnu.org/licenses/>. // * * * // This program creates 5 seperate threads which report over serial // when they're called. It can be tested by running the program and // watching the serial console. #include <mthread.h> // Our custom Thread: class FooThread : public Thread { public: FooThread(int id); protected: bool loop(); private: int id; }; FooThread::FooThread(int id) { this->id = id; } bool FooThread::loop() { // Die if requested: if(kill_flag) return false; // Print the status message: Serial.print("FooThread "); Serial.print(id); Serial.println(" called."); // Sleep for one second: sleep(1); return true; } void setup() { // Create five threads and add them to the main ThreadList: for(int i = 1; i <= 5; i++) main_thread_list->add_thread(new FooThread(i)); // Initialize the serial connection: Serial.begin(9600); delay(1000); } // jl
이 외에도 ArduinoThread 등 몇 가지 라이브러리가 더 있는걸로 알고 있습니다만, 사용 방법이나 구조는 유사합니다.