Nanashi-softプログラマ専用PS3 Linux SDL


◇PS3 Linux SDLでプログラミング -ミューテックスを使う-

○ミューテックス(Mutex)とは?

ミューテックスとはスレッド処理を行う際に、資源を共有する時に使います
例えば、2スレッドにて、特定の変数の値を見て処理を行う場合に、変数を見て処理を行う間にもう一方が変数を参照しては困る場合があります
そういう場合に、ミューテックスでロックをかけて処理を行います

○スレッド処理で問題が起こるプログラム例

int j=0; //スレッド処理結果を格納する変数
//スレッド実行する関数
int thread1(void* args){
  int i;
  int j2;
  for (i=51; i <= 100; i++){
    j2 = j;
    SDL_Delay(rand()%2);
    j2 = j2 + i;
    j = j2;
  }
}

int thread2(void* args){
  int i;
  int j2;
  for (i=1; i <= 50; i++){
    j2 = j;
    SDL_Delay(rand()%2);
    j2 = j2 + i;
    j = j2;
  }
}

int main(int args,char *argp[]){
  SDL_Thread *pt1, *pt2;
  pt1 = SDL_CreateThread(thread1, NULL); //スレッドを実行
  pt2 = SDL_CreateThread(thread2, NULL); //スレッドを実行

  SDL_WaitThread(pt1, NULL); //スレッド処理終了を待つ
  SDL_WaitThread(pt2, NULL); //スレッド処理終了を待つ

  printf("%d\n", j);
}

2レッドにて、jに値を加算する際に、どうしても一旦ローカル変数j2に入れて計算しなければならない設定、とします
SDL_Delayにて、その計算に時間がかかると言う設定を作ってみました

これを実行すると、1から100まで加算した5050にはなりません
なぜなら、グローバル変数jを取り出して処理している間に、もう一方のスレッドもjを取り出す事がある為です

○ミューテックスの使い方

考え方としては、ファイルの排他ロックと同じです
資源が必要になった時にロックを試みて、処理が終わったらロックを解除します
スレッド処理の場合は、予めロック用の変数ミューテックスを生成しておく違いがあります

・スレッド生成前にミューテックスを生成(SDL_CreateMutex)
・スレッド生成時にミューテックスを渡す
・スレッド処理中に共有資源にアクセスする場合はミューテックスをロックする(SDL_mutexP)
 注意)ロックが成功するまでブロッキングします
・共有資源の処理が終わった時点でアンロックする(SDL_mutexV)
・スレッドが終わってから、ミューテックスを破棄する(SDL_DestroyMutex)

ファイルのロックとの違いはシェアモードが無い点です
メモリアクセスの共有を前提とした設計のようで、あまり長時間占有するリソースには不向きです

○ミューテックスを利用したソース

#include "SDL.h"

int j=0; //スレッド処理結果を格納する変数
//スレッド実行する関数
int thread1(void* args){
  int i;
  int j2;
  SDL_mutex *mtx2 = (SDL_mutex *)args;
  for (i=51; i <= 100; i++){
    SDL_mutexP(mtx2); //ミューテックスをロック
    j2 = j;
    SDL_Delay(rand()%2);
    j2 = j2 + i;
    j = j2;
    SDL_mutexV(mtx2); //ミューテックスをアンロック
  }
}

int thread2(void* args){
  int i;
  int j2;
  SDL_mutex *mtx2 = (SDL_mutex *)args;
  for (i=1; i <= 50; i++){
    SDL_mutexP(mtx2); //ミューテックスをロック
    j2 = j;
    SDL_Delay(rand()%2);
    j2 = j2 + i;
    j = j2;
    SDL_mutexV(mtx2); //ミューテックスをアンロック
  }
}

int main(int args,char *argp[]){
  SDL_Thread *pt1, *pt2;
  SDL_mutex *mtx;

  mtx = SDL_CreateMutex(); //ミューテックスを生成

  pt1 = SDL_CreateThread(thread1, mtx); //スレッドを実行
  pt2 = SDL_CreateThread(thread2, mtx); //スレッドを実行

  SDL_WaitThread(pt1, NULL); //スレッド処理終了を待つ
  SDL_WaitThread(pt2, NULL); //スレッド処理終了を待つ

  SDL_DestroyMutex(mtx); //ミューテックスを破棄

  printf("%d\n", j);
}

このように共有資源をロックする事で、正しい結果を得る事ができます
但し、片方のスレッドが共有リソースを占有中、もう片方はロック待ちで停止するので、このプログラムはスレッド処理を行う意味が全くありません
スレッドプログラミングを行う際には、資源をどのように分散処理させるのかを設計段階で十分検討しておく必要があるのです


TOPプログラマ専用PS3 Linux SDL