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


◇PS3 Linux SDLでプログラミング -PPEでスレッド処理-

Cell内部の PowerPCはマルチコアではありませんが、強力なマルチスレッド機構を持ちます
プログラムをスレッド化する事で、計算能力を大幅にアップする事ができます

ここでの説明はLinux専用です。SDLにも標準でスレッドを生成するAPIがあり、そちらを使うほうが移植性が高くなります

○スレッドとは?

プログラムの実行単位をプロセスと呼びます
プログラム上の処理単位をスレッドと呼びます

例えば、1から 100までを足すプログラムと、101から 200まで足すプログラムを同時に実行すると、
2プロセスの各 1スレッドになります

1つのプログラム上で、1から 100まで足す処理と、101から 200まで足す処理を平行処理すると、
1プロセスの 2スレッドになります

……と、非常に分かり辛い概念ですので、私はグローバル変数の扱いで区別しています
プロセスが異なると、グローバル変数別物です
スレッド
が異なっても、グローバル変数同一です

○スレッド用の思考を持つ

以下のような 1から 100まで足すプログラムがあるとします

int i;
int j=0;
for (int i=1; i <= 100; i++){
  j = j + i;
}

この処理を 2つに分けるとすると、単純に 1~50と 51~100を足す方法が考えられます

int i;
int j=0;
for (int i=1; i <= 50; i++){
  j = j + i;
}
for (int i=51; i <= 100; i++){
  j = j + i;
}

このようなプログラムしか思いつかない人は、スレッド習得は遠いです(私みたいにw)
なにがマズいのかと言うと、この 2つの forループは平行動作できません。変数が重複しているからです

int i1;
int j1=0;
for (int i1=1; i1 <= 50; i1++){
  j1 = j1 + i1;
}

int i2;
int j2=0;
for (int i2=51; i2 <= 100; i2++){
  j2 = j2 + i;
}

int j;
j = j1 + j2;

これで、forループは全く別々に動作可能です

○スレッド化する

上で作成したプログラムを 2スレッド実行してみます
まず、基本として、スレッド実行するプログラムは関数化されていなければなりません
今回は j2の方を関数にしてみます

int j2;
void thread1(void* args){
  int i2;
  j2=0;
  for (int i2=51; i2 <= 100; i2++){
    j2 = j2 + i2;
  }
}

上で説明した通り、スレッド処理中のグローバル変数は同一です
値を渡すのが簡単ですので、今回はグローバル変数として j2を定義します

pthread_create関数を使用して、この thread1をスレッド実行します

pthread_t pt1;
pthread_create(&pt1, NULL, thread1, NULL);

このままでは、ブロッキングしないので、スレッド処理を投げっぱなしになります
そこで、スレッド処理の終了を検知する pthread_join関数を記述します

pthread_join(pt1, NULL);

スレッドの手続きそのものはこれだけで、難しいのはどのように分割するのか? と言うロジックの方なのです

○スレッドプログラム例

上の例をきちんとプログラム記述してみます

#include "stdio.h"
#include "pthread.h"  //スレッド用ヘッダー(Linux専用)

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

int main(int args,char *argp[]){
  pthread_t pt1;
  pthread_create(&pt1, NULL, thread1, NULL);  //スレッドを実行

  //メイン処理はそのまま平行動作している
  int i1;
  int j1=0;
  for (int i1=1; i1 <= 50; i1++){
    j1 = j1 + i1;
  }

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

  //両方のスレッドで処理した結果をまとめる
  int j;
  j = j1 + j2;
}

これで、メインスレッドと、生成した pt1スレッドが同時に計算します

○スレッドプログラム例・その2

この手の手法は、同じ結果のプログラムを別の方法でも書くと理解が深まります
上の例を、スレッド処理だけでやってみます

#include "stdio.h"
#include "pthread.h"  //スレッド用ヘッダー(Linux専用)

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

//上でメインスレッドで行っていた部分もスレッドにする
int j1;
void thread2(void* args){
  int i1;
  j1=0;
  for (int i1=1; i1 <= 50; i1++){
    j1 = j1 + i1;
  }
}
int main(int args,char *argp[]){
  pthread_t pt1;
  pthread_t pt2;
  pthread_create(&pt1, NULL, thread1, NULL);  //スレッドを実行
  pthread_create(&pt2, NULL, thread2, NULL);  //スレッドを実行

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

  //両方のスレッドで処理した結果をまとめる
  int j;
  j = j1 + j2;
}

これで、メインスレッドと、生成した p1スレッドと p2スレッドが同時に計算します
まぁ、メインスレッドは何もしないで待っているだけですがw

ここで、アレ? と思いませんか?
CPUが同時に実行できるのは、同時に 2スレッドなのに、このプログラムでは同時に 3スレッドになります
そこは、OSがなんとかしてくれていますので、プログラマは言うだけ~です(*'-')


TOPプログラマ専用PS3 Linux SDL

ネコミトリ 詰めピラミッド+メイナの実験場~裸マント文乃ちゃん~