C/C++マルチスレッドプログラミング/CPUバインド

5938 ワード

PthreadはPOSIXが提案した汎用スレッドライブラリで、linuxプラットフォームの下で広くサポートされていますが、windowsプラットフォームの下ではサポートされていません.pthreads-w 32はソリューションを提供しています.
マルチスレッドプログラミングにはヘッダファイル#includeを含める必要があります
#includeの関数long sysconf(_SC_NPROCESSORS_ONLN);現在のCPUのコア数を取得できます.
マルチスレッドプログラムはシングルコアCPUでも実行できますが、同じ時間に1つのスレッドしか走ることができません.システムはスレッドを切り替えてあげます.システムは各スレッドにタイムスライスを割り当てて実行します.各タイムスライスは10 msぐらいで、同時に走るように見えますが、実際には各スレッドが少し走ると他のスレッドに変えて走り続けます.
マルチスレッドプログラミングでは、CPUがタスクを完了するように指定できます.つまり、スレッドバインドです.指定しなくても、指定しない場合は、システムからCPUを自由に割り当てることができます.
 1. スレッドの作成pthread_create
関数のプロトタイプ:
int  pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(start_rtn)(void), void *restrict arg);

戻り値:成功すると0を返し、そうでない場合はエラー番号を返します.
パラメータ:
tidp:新しく作成されたスレッドIDを指す変数で、関数の出力として、このIDはスレッドを一意に指定し、他のスレッド関連関数はこのIDをパラメータとして必要とする(スレッド同期関数は不要).
attr:様々なスレッド属性をカスタマイズするために使用する、NULLはデフォルト属性である.
start_rtn:関数ポインタは、スレッドが実行を開始する関数名である.この関数はvoid*タイプの戻り値を返すことができ、この戻り値は他のタイプでpthread_join()取得
arg:関数の唯一のタイプレスポインタパラメータで、複数のパラメータを渡す場合は構造でカプセル化することができる.
pthread_createは一般的にmainで呼び出され、1回に1つのスレッドを作成するように呼び出されます.複数のスレッドが同じことをすると、3番目のパラメータ関数ポインタは同じになります.異なるスレッド間で異なることをすると、関数ポインタが異なり、異なるtask thread関数に対応します.
スレッドが作成された後、各スレッドにCPU、すなわちバインドを指定することができる.バインドしない場合は、システムによって自由に割り当てられます.
2.スレッド同期pthread_barrier_init/wait/destory
スレッド間の同期には、次の3つの関数、関数のプロトタイプが必要です.
int pthread_barrier_init(pthread_barrier_t *restrict barrier, const pthread_barrierattr_t *restrict attr, unsigned count);
int pthread_barrier_wait(pthread_barrier_t *barrier);
int pthread_barrier_destroy(pthread_barrier_t *barrier);

ここで、pthread_barrier_tはカウントロックであり,このロックに対する操作は3つの関数の内部に含まれており,関心もなく直接操作もできない.オブジェクトをインスタンス化して捨てるだけでいいです.パラメータはポインタであることに注意してください.一般的な直接インスタンス化pthread_barrier_t  g_barrier、そして&g_barrierは実パラメータとして関数に渡される.
pthread_barrierattr_t,ロックの属性設定,NULLに設定して関数にデフォルト属性を使用させておけばよい.
count、指定する待機個数.たとえば4つのスレッド間同期が必要な場合、countは4に設定されます.
pthread_barrier_initとpthread_barrier_destroyは、その名の通り、初期化と破棄であり、mainで呼び出され、呼び出されるのは1回だけです.
pthread_barrier_waitはブロック型待機であり,主にスレッド間同期に用いられる.コードがpthread_に実行されるとbarrier_waitの时、まずすべてのスレッドがwaitにあるかどうかをチェックして、もしすべてwaitにいたら、みんなでロックを解除します.
pthread_barrier_waitは作成されたスレッド関数(ここではtask thread関数と呼ぶ)で呼び出され、1つのtask thread関数ではpthread_を複数回呼び出すことができるbarrier_waitですが、すべてのtask thread関数で同じ回数が呼び出されることを保証する必要があります.
3.スレッド終了待ちpthread_join
int pthread_join(pthread_t thread, void **retval);

説明:pthread_join()関数は、threadで指定されたスレッドの終了をブロックするように待機します.関数が返されると、スレッドを待機していたリソースが回収されます.スレッドが終了すると、関数はすぐに返されます.threadで指定したスレッドはjoinableでなければなりません.
パラメータ:thread:スレッド識別子、すなわちスレッドIDは、一意のスレッドを識別します.retval:ユーザ定義のポインタで、待機スレッドの戻り値を格納し、一般的にNULLに設定します.
戻り値:0は成功を表します.失敗しました.エラー番号を返します.
リファレンスhttps://blog.csdn.net/qq_37858386/article/details/78185064
4.スレッドバインドCPU
リファレンスhttps://www.cnblogs.com/wenqiang/p/6049978.html
cpu親和性(affinity)は、固定されたCPUにバインドするために使用される.主に以下の関数があります.
int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);//      
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);//      
void CPU_ZERO (cpu_set_t *set)  /*     CPU   set      ,       。*/
void CPU_SET (int cpu, cpu_set_t *set) /*         cpu    CPU   set  */
void CPU_CLR (int cpu, cpu_set_t *set) /*         cpu   CPU   set    。*/
int CPU_ISSET (int cpu, const cpu_set_t *set)
/*   cpu   CPU   set    ,           (true),      (false)。*/
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);
int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize,  cpu_set_t *cpuset);

スレッドバインドCPUの具体的な操作は以下の通りです.https://blog.csdn.net/qq_26697045/article/details/89457241
以下は、ネットワークを参照して、自分で修正した例です.
/******
      pthread    g++ -g -Wall -pthread main.cpp -o sim
https://blog.csdn.net/qq_37858386/article/details/78185064
    64bit           
   error: cast from ‘void*’ to ‘int’ loses precision [-fpermissive]
      int id = (int) param;
      64bit      8   ,int     , void*   int        
     int id = (long) param;      
    void* task(void* param)      ,    return NULL;
         ,            
******/

#include 
#include 
#include 
#include 
struct my_para {
    int id;
    long aux;
};
pthread_barrier_t b;
void* task(void* param) {
    // int id = (long) param;
    my_para * t_para = (my_para * ) param;
    int id = t_para->id;
    delete t_para;
    
    for (int i = 0 ; i < 2 ; ++i){
        pthread_barrier_wait(&b);
        printf("loop = %d , before the barrier %d
", i, id); pthread_barrier_wait(&b); printf("loop = %d , after the barrier %d
", i, id); } return NULL; } int main() { int nThread = sysconf(_SC_NPROCESSORS_ONLN);//return long, but dont care printf(" cpu num : %d
", nThread); int i; pthread_t thread[nThread]; cpu_set_t t_mask; pthread_barrier_init(&b, 0, nThread); //initial barrier for (i = 0; i < nThread; i++) { my_para * t_para = new my_para; t_para->id = i; t_para->aux = i ; // thread[i] is returned by pthread_create pthread_create(&thread[i], NULL , task, t_para); printf(" i = %d, thread pid = %d
", i, thread[i]); // pthread_create(&thread[i], 0, task, (void*)i); //bend thread function to CPU CPU_ZERO(&t_mask); CPU_SET(i,&t_mask); pthread_setaffinity_np(thread[i],sizeof(cpu_set_t),&t_mask); } for (i = 0; i < nThread; i++) { pthread_join(thread[i], NULL); //wait thread function finish printf(" thread finish
" ); } pthread_barrier_destroy(&b); //destory barrier return 0; }