CodeZine(コードジン)

特集ページ一覧

pthreadについて(同期)

pthreadの同期方法

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2007/12/12 14:00
目次

3.同期(4/4):性能

3.6 性能

 最後に同期処理の性能比較を行います。 下記プログラムを実行し、ロック/アンロックの数値を出します。引数で与えられた数値の数だけスレッドを起動し、その中でひたすらロックとアンロックを20,000,000回繰り返します。プログラムのボリューム上、エラー処理および引数チェックを一切行っていないので、プログラムの先頭に書かれた実行方法以外では異常終了します。

lock_test.c
/*
* gcc lock_test.c -o lock_test -g -W -Wall -lpthread
* time ./lock_test <m|s|r|w> <1...8>
*/
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sys/time.h> #define LOOP_CNT 20000000 #define THR_CNT 8 pthread_mutex_t mutex; pthread_spinlock_t lock; pthread_rwlock_t rw_lock; void * spin_func ( void * arg ); void * mutex_func ( void * arg ); void * read_func ( void * arg ); void * write_func ( void * arg ); int main( int argc, char ** argv ) { ( void )argc; pthread_t id[THR_CNT]; int cnt = atoi( argv[2] ); int i; switch( *argv[1] ) { case 'm': pthread_mutex_init( &mutex, 0 ); for( i = 0; i < cnt; i ++ ) { pthread_create( &id[i], 0, mutex_func, 0 ); } break; case 's': pthread_spin_init( &lock, PTHREAD_PROCESS_PRIVATE ); for( i = 0; i < cnt; i ++ ) { pthread_create( &id[i], 0, spin_func, 0 ); } break; case 'r': pthread_rwlock_init( &rw_lock, 0 ); for( i = 0; i < cnt; i ++ ) { pthread_create( &id[i], 0, read_func, 0 ); } break; case 'w': pthread_rwlock_init( &rw_lock, 0 ); for( i = 0; i < cnt; i ++ ) { pthread_create( &id[i], 0, write_func, 0 ); } break; default: return 1; break; } pthread_exit( 0 ); return 0; } void * spin_func( void * arg ) { ( void )arg; int i; for( i = 0; i < LOOP_CNT; i ++ ) { pthread_spin_lock( &lock ); pthread_spin_unlock( &lock ); } return 0; } void * mutex_func( void * arg ) { ( void )arg; int i; for( i = 0; i < LOOP_CNT; i ++ ) { pthread_mutex_lock( &mutex ); pthread_mutex_unlock( &mutex ); } return 0; } void * read_func( void * arg ) { ( void )arg; int i; for( i = 0; i < LOOP_CNT; i ++ ) { pthread_rwlock_rdlock( &rw_lock ); pthread_rwlock_unlock( &rw_lock ); } return 0; } void * write_func( void * arg ) { ( void )arg; int i; for( i = 0; i < LOOP_CNT; i ++ ) { pthread_rwlock_wrlock( &rw_lock ); pthread_rwlock_unlock( &rw_lock ); } return 0; }

 私の環境では以下の通りとなりました。

表1 性能表
種類 thread:1 threads:2 threads:4 threads:8
mutex(real) 0m4.312s 0m8.258s 0m16.648s 0m32.537s
mutex(user) 0m4.289s 0m8.248s 0m16.626s 0m32.483s
mutex(sys) 0m0.004s 0m0.001s 0m0.005s 0m0.014s
spin(real) 0m3.108s 0m10.067s 0m33.643s 2m21.928s
spin(user) 0m3.101s 0m10.052s 0m33.582s 2m21.747s
spin(sys) 0m0.002s 0m0.004s 0m0.003s 0m0.010s
read lock(real) 0m6.659s 0m13.882s 0m26.806s 0m53.334s
read lock(user) 0m6.652s 0m13.863s 0m26.762s 0m53.252s
read lock(sys) 0m0.002s 0m0.005s 0m0.004s 0m0.014s
write lock(real) 0m6.804s 0m13.724s 0m44.236s 2m17.293s
write lock(user) 0m6.778s 0m13.694s 0m33.246s 1m25.993s
write lock(sys) 0m0.001s 0m0.022s 0m10.934s 0m50.971s

 私の環境だけで結論を出す事はできないので、あくまで参考値として見ていただければと思います。

 こうしてみると、spinは単一スレッドの場合は最速ですがスレッド数が上がるに連れて遅くなります。スレッド数が上がるにつれCPU使用率がネックになって処理が進まないのでしょう。

 ちなみにCPUを複数抱えている環境、例えば4個のCPUを持つ環境では、threads:4までは少なくともmutexよりも高速に動作するはずです。クリティカルセクションが狭く、スレッド数がCPU数と比べて少ない場合はspinの使用が適してます。

 特にそのような状況では無い場合ではmutexの使用が良いと思います。

 write lockはさすがに性能が良くないです。これはwrite lockを行う際にread/writeを行っているスレッドがいない事を確認している為です。シビアな性能を求められない状況ならば、read/write lockは使いたい機能です。

 次回は条件変数と、今までの機能で作った簡単なアプリケーションを紹介します。



  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:pthreadについて

もっと読む

著者プロフィール

  • 赤松 エイト(エイト)

    (株)DTSに勤てます。 WebアプリやJavaやLL等の上位アプリ環境を密かに憧れつつも、ず~っとLinuxとかHP-UXばかり、ここ数年はカーネル以上アプリ未満のあたりを行ったり来たりしています。 mixiもやってまして、こちらは子育てとか日々の日記メインです。

あなたにオススメ

All contents copyright © 2005-2022 Shoeisha Co., Ltd. All rights reserved. ver.1.5