pthread mutex lockとAtomic型修飾子の比較
提供: C言語入門
スポンサーリンク
C言語のマルチスレッドプログラミングでよく使われるpthreadでは、アトミックな処理のために mutex を使用してロックします。また、C言語では、_Atomic型修飾子を利用して、アトミックな処理ができます。ここでは、pthread_mutex_lockを利用した場合と _Atomic を利用したアトミックなプログラムのスピードの比較を行います。
読み方
目次
概要
ロックなしは、ロックがないため、期待した結果をしないプログラムです。なぜか、コンパイラのコンパイルオプションの -O2 で最適化した場合は、結果が 0 になり、期待した結果になっていました。
mutex と _Atomic の比較では、 _Atomic > mutex lock という結果になりました。
タイプ | user | system | cpu | total |
---|---|---|---|---|
ロックなし | 0.04s | 0.01s | 189% | 0.024 |
mutex | 0.26s | 0.16s | 157% | 0.265 |
_Atomic | 0.28s | 0.00s | 196% | 0.142 |
mutex のロックは、コストが高い、ということでしたが、アトミックを使ったほうが、今回の単純なケースでは、速い、ということが解りました。 また、_Atomicを利用した場合のほうが、ソースコードも簡単になります。 pthread_mutex_lockを使うと pthread_mutex_unlock の呼び出しも必要になり、コードが汚くなってしまいます。
ヘッダファイル
#include <stdatomic.h>
サンプルコードの意味
- 2つのスレッドを同時に実行します。
- 片方の1つのスレッドは、グローバル変数 shared_data をインクリメントし続けます。
- もう1つのスレッドは、グローバル変数 shared_data をデクリメントし続けます。
- 最終的に 0 になることを期待します。
- ロックなしのコードは、アトミックに処理できないので、結果は不定です(0かもしれないし、0以外かもしれない)。
pthread_test1_no_block.c
このコードでも -O2 のオプションをつけると、結果が 0 になります。
ソースコード
// Last update: 2016/02/13 15:52:56 #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <err.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <pthread.h> int shared_data = 0; unsigned long long int max = 3000000; void func1 (int x) { unsigned long long int i; for (i = 0; i < max; ++i) { ++shared_data; } } void func2 (int x) { unsigned long long int i; for (i = 0; i < max; ++i) { --shared_data; } } void test () { pthread_t t1, t2; pthread_setconcurrency (2); pthread_create (& t1, NULL, (void *) func1, (void *) 10); pthread_create (& t2, NULL, (void *) func2, (void *) 20); pthread_join (t1, NULL); pthread_join (t2, NULL); } int main (int argc, char **argv) { int i; test (); printf ("%u\n", shared_data); printf ("END\n"); exit (EXIT_SUCCESS); }
pthread_test1_mutex
ソースコード
// Last update: 2016/02/13 15:52:56 #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <err.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <pthread.h> pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; int shared_data = 0; unsigned long long int max = 3000000; void func1 (int x) { unsigned long long int i; for (i = 0; i < max; ++i) { int r; r = pthread_mutex_lock(&m); if (r != 0) { errc(EXIT_FAILURE, r, "can not lock"); } ++shared_data; r = pthread_mutex_unlock(&m); if (r != 0) { errc(EXIT_FAILURE, r, "can not unlock"); } } } void func2 (int x) { unsigned long long int i; for (i = 0; i < max; ++i) { int r; r = pthread_mutex_lock(&m); if (r != 0) { errc(EXIT_FAILURE, r, "can not lock"); } --shared_data; r = pthread_mutex_unlock(&m); if (r != 0) { errc(EXIT_FAILURE, r, "can not unlock"); } } } void test () { pthread_t t1, t2; pthread_setconcurrency (2); pthread_create (& t1, NULL, (void *) func1, (void *) 10); pthread_create (& t2, NULL, (void *) func2, (void *) 20); pthread_join (t1, NULL); pthread_join (t2, NULL); } int main (int argc, char **argv) { int i; test (); printf ("%u\n", shared_data); printf ("END\n"); exit (EXIT_SUCCESS); }
pthread_test1_atomic.c
ソースコード
// Last update: 2016/02/13 15:52:56 #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <err.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <pthread.h> #include <stdatomic.h> _Atomic int shared_data = ATOMIC_VAR_INIT(0); unsigned long long int max = 3000000; void func1 (int x) { unsigned long long int i; for (i = 0; i < max; ++i) { ++shared_data; } } void func2 (int x) { unsigned long long int i; for (i = 0; i < max; ++i) { --shared_data; } } void test () { pthread_t t1, t2; pthread_setconcurrency (2); pthread_create (& t1, NULL, (void *) func1, (void *) 10); pthread_create (& t2, NULL, (void *) func2, (void *) 20); pthread_join (t1, NULL); pthread_join (t2, NULL); } int main (int argc, char **argv) { int i; test (); printf ("%u\n", shared_data); printf ("END\n"); exit (EXIT_SUCCESS); }
コンパイル
cc -pthread pthread_test1_atomic.c -o pthread_test1_atomic cc -pthread pthread_test1_mutex.c -o pthread_test1_mutex cc -pthread pthread_test1_no_block.c -o pthread_test1_no_block
実行例
薫 $ time ./pthread_test1_no_block 509710 END ./pthread_test1_no_block 0.04s user 0.01s system 189% cpu 0.024 total 薫 $ time ./pthread_test1_mutex 0 END ./pthread_test1_mutex 0.26s user 0.16s system 157% cpu 0.265 total 薫 $ time ./pthread_test1_atomic 0 END ./pthread_test1_atomic 0.28s user 0.00s system 196% cpu 0.142 total
関連項目
ツイート
スポンサーリンク