참조 : 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 등 몇 가지 라이브러리가 더 있는걸로 알고 있습니다만, 사용 방법이나 구조는 유사합니다.