0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

InterlockedIncrementを使用してマルチスレッド化

Posted at

Windowsの古いプログラムの性能を改善するために、マルチスレッド化する方法を考えてみた。プログラムでは、配列の各要素に対してある処理を順番に実行している。処理はメモリの読み書きのみで互いに独立。
InterlockedIncrementSleepを使うと比較的簡単に実装できることが分かった。

サンプルプログラムの親スレッドでは、開始スレッド数と終了スレッド数の差が上限値未満ならば、新しい子スレッドを開始して、開始スレッド数をカウントアップする。そうでなければ一定時間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
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?