Windowsの古いプログラムの性能を改善するために、マルチスレッド化する方法を考えてみた。プログラムでは、配列の各要素に対してある処理を順番に実行している。処理はメモリの読み書きのみで互いに独立。
InterlockedIncrement
とSleep
を使うと比較的簡単に実装できることが分かった。
サンプルプログラムの親スレッドでは、開始スレッド数と終了スレッド数の差が上限値未満ならば、新しい子スレッドを開始して、開始スレッド数をカウントアップする。そうでなければ一定時間Sleep
する。
サンプルプログラムの子スレッドでは、ある時間Sleep
してからデータの一部を更新する。終了する際に終了スレッド数をカウントアップする。Sleep
する時間は乱数で決定。
当初、乱数は子スレッドで生成していたが、常に同じ値が返ってきた。乱数の初期化は親スレッドで実行していて、子スレッドはその環境をコピーするため。乱数を親スレッドで生成して引数で渡すように修正。
# include <stdio.h>
# include <windows.h>
# include <process.h>
# include <errno.h>
# include <string.h>
// thread parameters
struct cparam {
LONG* p_end;
LONG* p_error;
int no;
int sleep;
int* data;
};
// thread function
void __cdecl fun(void *p) {
cparam* pp = (cparam*)p;
try {
printf("start,%d,%d\n", pp->no, pp->sleep);
Sleep(pp->sleep * 1000);
pp->data[pp->no] = pp->no;
printf("end,%d,%d\n", pp->no, pp->sleep);
}
catch (...) {
InterlockedIncrement(pp->p_error);
}
InterlockedIncrement(pp->p_end);
delete pp;
}
void main_thread() {
const int N = 10;
int data[N];
for (int i = 0; i < N; i++) data[i] = 0;
srand(10);
LONG n_start = 0;
LONG n_end = 0;
LONG n_error = 0;
int limit = 5;
// execute function for each element
int n = 0;
while (N > n) {
if (n_start - n_end < limit) {
cparam* pp = new cparam();
pp->p_end = &n_end;
pp->p_error = &n_error;
pp->no = n;
pp->sleep = (rand() % 10) + 1;
pp->data = data;
uintptr_t th = _beginthread(fun, 0, pp);
if (th == -1L) {
// error
int errnum = errno;
printf("errno,%d,%s\n", errnum, strerror(errnum));
delete pp;
}
else {
n_start++;
}
n++;
}
else {
Sleep(250);
printf(".\n");
}
}
// wait for child threads
while (n_start > n_end) {
Sleep(250);
printf(".\n");
}
printf("%d,%d,%d\n", n_start, n_end, n_error);
}
- 子スレッドのハンドルは必要ないので、
_beginthreadex
の代わりに、_beginthread
を使用。 -
_endthread
は、fun
が終了すると自動的に呼び出されるため、省略。 -
InterlockedDecrement
を使用してスレッド数を一つにまとめるのもあり。
実行結果
start,0,2
start,1,10
start,3,5
start,4,8
start,2,3
.
.
.
.
.
.
.
end,0,2
.
start,5,7
.
.
.
end,2,3
.
start,6,3
.
.
.
.
.
.
end,3,5
.
start,7,3
.
.
.
.
end,6,3
.
start,8,7
.
.
.
.
.
.
end,4,8
end,7,3
.
start,9,10
.
.
.
end,5,7
.
.
.
end,1,10
.
.
.
.
.
.
.
.
.
.
.
.
.
end,8,7
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
end,9,10
.
10,10,0