C言語でのスレッド処理
C言語でのスレッド処理と、ロックの仕方をまとめました。
他の言語のようにスレッド用のクラスを継承するのでは無く、
別スレッドで実行する関数のポインタと、
その関数に渡すデータのポインタを指定して実行するようです。
スレッドによる並行処理
スレッドの作成(pthread_create)
Cではpthread_createを利用することで、別スレッドで任意の関数を実行できます。
int pthread_create(pthread_t * thread,
pthread_attr_t * attr,
void * (*start_routine)(void *),
void * arg);
- thread
- スレッド管理用のpthread_t型の変数
- attr
- スレッドの属性を指定する。
- NULLの場合はデフォルトが使われる
- (*start_routine)(void *)
- 別スレッドから呼び出される関数へのポインタ
- arg
- start_routineの引数として渡すデータのポインタ
- 元のスレッドからデータを送るのに使う
スレッドの終了を待つ(pthread_join)
pthread_joinで、指定したスレッドが終了するまで待機することができます。
int pthread_join(pthread_t th, void **thread_return);
- th
- 待機するスレッドをpthread_t型の変数で指定する
- **thread_return
- スレッドの戻り値を格納する領域
サンプルコード
以下の例はグローバルな値にメインとサブの2つのスレッドから加算処理を行っています。
排他制御をしていないため、スレッドによる並行処理が行われると、値がおかしくなる可能性があります。
実際、何度か実行すると値がおかしくなり、並行処理が行われていることが確認できます。
なお、コンパイルする際はは-pthreadオプションを指定する必要があります。
#include "stdio.h"
#include "pthread.h"
int a = 0;
void *func_thread(void *p) {
printf("start %d\n", *(int*)p);
int i=0;
for(i=0; i < 10000; i++){
int next = a + 1;
int now = a;
a = next;
if (now+1 != next) {
printf("other theard change %d %d\n", a+1, next);
}
}
return 0;
}
int main(void) {
printf("test\n");
int b = 42;
pthread_t pthread;
pthread_create( &pthread, NULL, &func_thread, &b);
int i=0;
for(i=0; i < 10000; i++){
int next = a + 1;
int now = a;
a = next;
if (now+1 != next) {
printf("other theard change %d %d\n", a+1, next);
}
}
pthread_join(pthread, NULL); // pthreadで作られたスレッドが終わるまで待つ
printf("a=%d\n", a);
return 0;
}
mutexによるロック処理
排他制御を行う
pthread_mutex_t
型の変数に対して、pthread_mutex_lock
、pthread_mutex_unlock
を実行することで、
処理をロックすることができます。
pthread_mutex_t
型の変数はpthread_mutex_init
で初期化することができます。
このとき、第二引数にmutex属性を渡すことができ、NULLを渡した場合はデフォルト値が使われます。
サンプルコード
上記の例にロックによる排他制御を入れました。
そのため、並列処理を行っても値は正しく処理されるため、何度やっても結果が正しくなります。
#include "stdio.h"
#include "pthread.h"
int a = 0;
pthread_mutex_t mutex;
void *func_thread(void *p) {
printf("start %d\n", *(int*)p);
int i=0;
for(i=0; i < 10000; i++){
pthread_mutex_lock(&mutex);
int next = a + 1;
int now = a;
a = next;
pthread_mutex_unlock(&mutex);
if (now+1 != next) {
printf("other theard change %d %d\n", a+1, next);
}
}
return 0;
}
int main(void) {
pthread_mutex_init(&mutex, NULL);
printf("test\n");
int b = 42;
pthread_t pthread;
pthread_create( &pthread, NULL, &func_thread, &b);
int i=0;
for(i=0; i < 10000; i++){
pthread_mutex_lock(&mutex);
int next = a + 1;
int now = a;
a = next;
pthread_mutex_unlock(&mutex);
if (now+1 != next) {
printf("other theard change %d %d\n", a+1, next);
}
}
pthread_join(pthread, NULL); // pthreadで作られたスレッドが終わるまで待つ
printf("a=%d\n", a);
return 0;
}