2012年09月26日

Propeller gccでpthreadライブラリを使ってマルチタスクしてみる

以前プロペラのgccがあるよ、という話を伺った時、propellerスレッドライブラリあったら面白いねーとか話していたのですが、Pellerduinoのコア(PellerduinoCore)をいじってて、普通にpthreadライブラリあるじゃないかと気づきました。

プロペラのpthread実装がどのようなコードになっているのか、非常に気になるところです。
その前にひとまず、pthreadライブラリを使ってマルチタスクがお手軽に出来るのか?を実験をしてみることにしました。

Propeller_QS.jpg
以下がテスト用に作成したコード。
/*
  LED Blink test for QuickStart board

  Coded by Yasuhiro ISHII
*/

#include 

extern "C" {
#include 
}

#include 

const int pinTable[8] = {
    PIN_LED0,
    PIN_LED1,
    PIN_LED2,
    PIN_LED3,
    PIN_LED4,
    PIN_LED5,
    PIN_LED6,
    PIN_LED7
};

pthread_t th[8];
pthread_mutex_t gpio_mutex;
void synchronized_digitalWrite(int port,int level);

void busywait(unsigned int usecs);

void* thread(void* arg)
{
    int i;

    i = (int)arg;
    pinMode(pinTable[i],OUTPUT);

    while(1){
	printf("thread [%d]\n",i);
	synchronized_digitalWrite(pinTable[i],HIGH);
	delay((i+1)*100);
	synchronized_digitalWrite(pinTable[i],LOW);
	delay((i+1)*100);
    }
}

void synchronized_digitalWrite(int port,int level)
{
    pthread_mutex_lock(&gpio_mutex);

    digitalWrite(port,level);

    pthread_mutex_unlock(&gpio_mutex);
}

void busywait(unsigned int usecs)
{
  volatile unsigned long cycles = usecs * (_clkfreq/1000000);
  volatile unsigned long then = _CNT + cycles;
  while((long)(then - _CNT) > 0){
//      pthread_yield(); 
  }
}

void setup()
{
    int i;

    pthread_mutex_init(&gpio_mutex,NULL);

    for(i=0;i<8;i++){
      pinMode(pinTable[i],OUTPUT);
    }

    for(i=0;i<8;i++){
	pthread_create(&th[i],NULL,thread,(void*)i);
    }
}

void loop()
{

}
Pellerduinoはpthread.aをリンクしてないので、ひとまず以下のMakefileにてビルド。
# Propeller build Makefile
#
# Yasuhiro ISHII 2012
# ishii.yasuhiro@gmail.com

CROSS_ENV	=  propeller-elf-
CC		=  $(CROSS_ENV)gcc
CPP		=  $(CROSS_ENV)g++
CFLAGS		=  -Os -I. -fno-exceptions -mlmm -lpthread -pthread
CPPFLAGS	=  -Os -I. -fno-exceptions -mlmm -lpthread -pthread
LCFLAGS		=  -pthread -lpthread
TARGET		=  target.elf
OBJS		=  main.o
DOWNLOADER	=  propeller-load
DLOPT		=  -r


COMMONOBJS	=  PellerduinoCore.o

OBJS		+= $(COMMONOBJS)
#CFLAGS		+= -Wall -mcog

.c.o:
	$(CC) $(CFLAGS) -c $<
.cpp.o:
	$(CPP) $(CPPFLAGS) -c $<

$(TARGET) : $(OBJS)
	$(CC) -o $@ $(OBJS) $(LCFLAGS)


.PHONY: clean
clean:
	-rm $(OBJS) $(TARGET) $(COMMONOBJS)

.PHONY: purge
purge:
	-rm *~

.PHONY: download
download:
	$(DOWNLOADER) $(DLOPT) $(TARGET)
コードはPellerduinoCoreからの呼び出しになっているので、Arduino同様、setup()→loop()で実行されます。
setup関数内で、I/O操作用のmutexをpthread_mutex_init関数で行った後、pthread_create関数で8スレッド起動しています。digitalWriteは同一ポート資源のコントロールをするので、スレッドからは、mutexで排他性を確保したsynchronized_digitalWriteを呼ぶようにしています。
それぞれのスレッドにそれぞれ1つのLEDを点滅させるのですが、スレッドに渡す引数の値で点滅周期が変化するようにしているので、バラバラの点滅パターンになっているように見えるはずです。
loop関数は空関数で何もしません。

動画はこちら。

なんとなく、Arduinoっぽいコードの枠組み内にpthreadを使用したマルチタスクの処理とか非常に不思議な感じのコードになってますが、以下の動画のように、なんとなくうまく動いてるようです。
複数のcogが使われているのか否かなどは、調べていきたいと思います。
もしかすると、複数cogで実行している場合、gpioのmutexは不要かもしれません。(I/Oの資源も個々に独立しているのなら)

コードは以下のPellerduinoCoreにも入っています。
https://github.com/yishii/PellerduinoCore
Netduino(Arduinoピンコンパチ.NETマイコンボード)
Secret Labs LLC
売り上げランキング: 59733
Pthreadsプログラミング
Pthreadsプログラミング
posted with amazlet at 12.09.26
Bradford Nichols Dick Buttlar Jacqueline Proulx Farrel
オライリー・ジャパン
売り上げランキング: 238987
posted by いしいっち at 22:08| Comment(0) | TrackBack(0) | 日記 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバック
×

この広告は90日以上新しい記事の投稿がないブログに表示されております。