Linux の POSIX スレッド

簡単な説明

POSIXスレッドは、プログラマが複数のスレッドを使用してタスクを同時に実行できるようにする関数とデータ型のセットを提供する(Pthreads)標準的なマルチスレッドです。スレッド サポートは、クラス オペレーティング システム上で動作し、クロスプラットフォームです。APIPOSIXUnix

方法

以下は、一般的に使用されるPOSIXスレッド関数とデータ型の一部です。

pthread_t

不透明な構造体型であるスレッドのデータ型を表し、通常はスレッド制御ブロック (スレッド制御ブロック、TCB) へのポインターとして実装されます。<pthread.h>ヘッダファイルで定義

pthread_create()

この関数は、新しいスレッドを作成するために使用されます。そのプロトタイプは次のとおりです。

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

パラメータの説明:

  • thread: 新しいスレッドを指しますID。スレッドが正常に作成されると、新しいスレッドとして埋められますID
  • attr: 新しいスレッドのプロパティを設定するために使用されます。渡された場合NULL、デフォルトのスレッド プロパティが使用されます。
  • start_routine: 新しいスレッドのエントリ関数です。新しいスレッドによって実行される関数を指す関数ポインタです。
  • arg:start_routine関数

pthread_create()関数が呼び出されると、新しいスレッドが作成され、新しいスレッドがstart_routine関数を実行します。start_routine関数が正常に実行され、正常に終了すると、新しいスレッドは自動的に終了し、pthread_join()関数を呼び出すことで新しいスレッドの終了ステータスを取得できます。start_routine関数でエラーが発生した場合、または異常終了した場合

pthread_join()

スレッドの終了を待ち、その終了ステータスを取得する関数。そのプロトタイプは次のとおりです。

int pthread_join(pthread_t thread, void **retval);

パラメータの説明:

  • thread: 待機するスレッドID
  • retval: スレッドの戻り値NULL

pthread_exit()

この関数は、スレッド内でスレッドを終了するために使用されます。値を返すことも、何も返さないこともあります。

void pthread_exit(void *value_ptr);

パラメータの説明:

  • value_ptr: スレッドの終了ステータスとして、スレッドの実行を他のスレッドに通知します。

pthread_mutex_t

このデータ型はミューテックスを表します。ミューテックスは、共有リソースへのアクセスを制御するために使用される同期メカニズムです。そのプロトタイプは次のとおりです。

typedef struct {
    
    
    // ...
} pthread_mutex_t;

pthread_mutex_init()

この関数は、ミューテックスを動的に初期化するために使用されます。そのプロトタイプは次のとおりです。

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);

またPTHREAD_MUTEX_INITIALIZER、静的に定義されたミューテックス、つまりコンパイル時に決定されたミューテックスの場合。

eg:

static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;

パラメータの説明:

  • mutex: 初期化するミューテックス。
  • attr: ミューテックスの属性NULL

pthread_mutex_lock()

この関数はミューテックスを取得するために使用されます。ミューテックスが別のスレッドによって既に保持されている場合、現在のスレッドはブロックされます。そのプロトタイプは次のとおりです。

int pthread_mutex_lock(pthread_mutex_t *mutex);

パラメータの説明:

  • mutex: 取得するミューテックス。

pthread_mutex_unlock()

この関数はミューテックスを解放するために使用されます。そのプロトタイプは次のとおりです。

int pthread_mutex_unlock(pthread_mutex_t *mutex);

パラメータの説明:

  • mutex: 解放するミューテックス。

pthread_mutex_destroy()

ミューテックスを破棄するために使用される関数、そのプロトタイプは次のとおりです。

int pthread_mutex_destroy(pthread_mutex_t *mutex);

パラメータの説明:

  • mutex: ミューテックスへのポインタ。

pthread_cond_t

このデータ型は、スレッド間で条件変数の同期を実現する (つまり、異なるスレッド間でシグナルを渡す) ために使用されます。pthread_cond_wait()、 、などの関数でよく使用されます。そのプロトタイプは次のとおりです。pthread_cond_signal()pthread_cond_broadcast()

typedef struct {
    
    
    // ...
} pthread_cond_t;

条件変数は、pthread_cond_init()またはで初期化できます。PTHREAD_COND_INITIALIZER

pthread_cond_init()

この関数は、条件変数を初期化するために使用されます。そのプロトタイプは次のとおりです。

int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);

パラメータの説明:

  • cond: 初期化する条件変数。
  • attr: 条件変数のプロパティ。NULL にすることができます。

pthread_cond_wait()

この関数の機能は、条件変数の値がゼロ以外になるのを待っている間にスレッドをブロックし、条件変数が別のスレッドからのシグナルによって起こされるのを待つことです。
スレッドがそれを呼び出すと、別のスレッドが呼び出すか、条件が満たされたことが通知されるpthread_cond_wait()までブロックされます。そのプロトタイプは次のとおりです。pthread_cond_signal()pthread_cond_broadcast()

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

パラメータの説明:

  • cond: 条件変数ポインタ。
  • mutex: ミューテックス ポインター。この関数を呼び出す前にロックを取得する必要があり、ロックは関数が戻る前に自動的に解放されます。

pthread_cond_signal()

条件変数で待機しているスレッドにシグナルをブロードキャストし、条件変数で待機しているスレッドを起床させるために使用されます. 待機しているスレッドが複数ある場合は、そのうちの 1 つだけが起床されます. 待機中のスレッドがない場合、この操作は効果がありません。通常、スレッド間で条件変数を同期するために とpthread_cond_wait()組み合わせて。

int pthread_cond_signal(pthread_cond_t *cond);

パラメータの説明:

  • cond: 条件変数ポインタ。

pthread_cond_broadcast()

条件変数を待機しているスレッドにシグナルをブロードキャストして、条件変数を待機しているすべてのスレッドをウェイクアップするために使用されます。通常、スレッド間で条件変数を同期するために とpthread_cond_wait()組み合わせて。そのプロトタイプは次のとおりです。

int pthread_cond_broadcast(pthread_cond_t *cond);

パラメータの説明:

  • cond: 条件変数ポインタ。

pthread_cond_destroy()

条件変数を破棄する関数。そのプロトタイプは次のとおりです。

int pthread_cond_destroy(pthread_cond_t *cond);

sem_t

これは、セマフォを表すために使用される、<semaphore.h>ヘッダー。sem_t変数は通常、sem_init()関数、使用が完了するとsem_destroy()関数によって破棄されます

sem_init()

セマフォの初期化に使用されます。そのプロトタイプは次のとおりです。

int sem_init(sem_t *sem, int pshared, unsigned int value);

パラメータの説明:

  • sem: 初期化する必要があるセマフォ変数へのポインター。
  • pshared: セマフォのタイプを指定します。値は0または1psharedの値が is の場合0、セマフォは現在のプロセスの複数のスレッド間でのみ共有できることを意味します;psharedの値1が is の場合、セマフォは複数のプロセス間で共有できることを意味します。
  • value: セマフォの初期値を指定します。セマフォの値は、使用可能なリソースの量を表す負でない整数でなければなりません。通常、初期値の は 1 つのリソースのみが使用可能である1ことを示し、初期値の0は使用可能なリソースがないことを示します。

sem_wait()

セマフォを取得 (待機) するために使用されます。つまり、セマフォに対して P 操作を実行します (待機操作: スレッドまたはプロセスがリソースを占有する必要がある場合、セマフォを取得するために P 操作を実行しようとします。セマフォが 0 より大きい場合は、セマフォの値を減らして実行を継続します。そうでない場合、スレッドまたはプロセスは、セマフォの値が 0 より大きくなるのを待ってブロックします)。

int sem_wait(sem_t *sem);

パラメータの説明:

  • sem: セマフォ変数へのポインタ。

sem_post()

セマフォを解放 (送信) するために使用されます。つまり、セマフォに対して V 操作を実行します (解放操作: スレッドまたはプロセスがリソースを占有する必要がなくなった場合、V 操作を実行してセマフォを解放します。この操作により、セマフォ 1 の値を使用して、実行を続行できることを他のスレッドまたはプロセスに通知します)。

int sem_post(sem_t *sem);

パラメータの説明:

  • sem: セマフォ変数へのポインタ。

sem_destroy()

初期化されたセマフォを破棄するために使用されます。そのプロトタイプは次のとおりです。

int sem_destroy(sem_t *sem);

パラメータの説明:

  • sem: セマフォ変数へのポインタ。

pthread_key_t

スレッド プライベート データ (Thread-Specific Data略してTSD) の作成に使用されます。スレッド プライベート データとは、各スレッドが独立したデータ空間を持ち、スレッド間のデータが互いに影響しないことを意味します。マルチスレッド プログラムでは、スレッドが独立してデータにアクセスし、データを変更できるように、スレッドごとに独立したデータ スペースを割り当てる必要がある場合があります。

pthread_key_create()

スレッド プライベート データのキーを作成します。

int pthread_key_create(pthread_key_t *key, void (*destructor)(void*))

パラメータの説明:

  • key: 作成されたスレッドのプライベート データのキーを格納するために使用されるpthread_key_t
  • destructor : は、スレッドの終了時にスレッドのプライベート データを自動的に解放するために使用されるコールバック関数です。スレッド プライベート データを自動的に解放する必要がない場合は、destructorパラメータNULL
  • 関数が正常に実行された場合は 0 を返し、それ以外の場合はゼロ以外のエラー コードを返します。

pthread_setspecific()

現在のスレッドのスレッド プライベート データを設定する

int pthread_setspecific(pthread_key_t key, const void *value)

パラメータの説明:

  • key: スレッドのプライベート データのキーです。
  • value: データへのポインタであり、スレッドのプライベート データの値を設定するために使用されます
  • 関数が正常に実行された場合は 0 を返し、それ以外の場合はゼロ以外のエラー コードを返します。

pthread_getspecific()

現在のスレッドのスレッド プライベート データを取得する

void *pthread_getspecific(pthread_key_t key)

パラメータの説明:

  • key: スレッド専用データのキーであり、スレッド専用データの値を取得するために使用されます。
  • この関数は、スレッド プライベート データへのポインタを返します。スレッドがスレッド プライベート データを設定しない場合は、 を返しますNULL

pthread_key_delete()

スレッド プライベート データのキーを削除します

int pthread_key_delete(pthread_key_t key)

パラメータの説明:

  • key: スレッド プライベート データのキー。キーと対応するスレッド プライベート データを削除するために使用されます。
  • スレッド プライベート データ キーが正常に削除された場合、関数は 0 を返します。それ以外の場合は、ゼロ以外のエラー コードを返します。

pthread_once_t

POSIXpthread_once 関数の制御変数を表すために使用されるスレッド ライブラリの型で、関数が 1 回だけ実行されるようにするために使用されます。これは実際には volatile int 型、volatileつまりint型変数であるため、この変数の値の読み取りおよび書き込み操作がマルチスレッド プログラムで最適化または再順序付けされないことが保証されます。

そのプロトタイプは次のとおりです。

typedef volatile int pthread_once_t;

pthread_once_t変数の初期化には、ヘッダー ファイルで定義されているPTHREAD_ONCE_INITマクロを使用する必要があり、その定義は次のとおりです。pthread.h

#define PTHREAD_ONCE_INIT   0

pthread_once_t変数は静的変数またはグローバル変数でなければならないことに注意してください。そうしないと、競合状態が発生する可能性があります。さらに、pthread_once_t 変数、変数を使用する場合はメモリ モデルと同期メカニズムに従う必要があります。

pthread_key_delete()

関数が一度だけ実行されるようにするために使用されます。マルチスレッド プログラミングでは、複数のスレッドが同じ初期化関数を実行する必要がある場合、pthread_once 関数を使用して関数が 1 回だけ実行されるようにすることで、同時アクセスによる競合状態の問題を回避できます。
そのプロトタイプは次のとおりです。

int pthread_once(pthread_once_t* once_control, void (*init_func)(void));

パラメータの説明:

  • once_control: pthread_once_t 型の変数へのポインタ
  • init_func: 一度だけ実行されることを保証する必要がある初期化関数を示す関数ポインタ

スレッドを作成

#include <pthread.h>
#include <stdio.h>

void *thread_function(void *arg) {
    
    
  printf("Hello from thread!\n");
  pthread_exit(NULL);
}

int main() {
    
    
  pthread_t my_thread;
  int ret = pthread_create(&my_thread, NULL, thread_function, NULL);
  if (ret != 0) {
    
    
    printf("Failed to create thread.\n");
    return -1;
  }
  printf("Thread created.\n");
  pthread_join(my_thread, NULL);
  printf("Thread joined.\n");
  return 0;
}
/*
执行结果:
Thread created.
Hello from thread!
Thread joined.
*/

パラメータをスレッドに渡す

#include <pthread.h>
#include <stdio.h>

void *thread_function(void *arg) {
    
    
  int *num_ptr = (int *)arg;
  printf("Hello from thread! The number is %d.\n", *num_ptr);
  pthread_exit(NULL);
}

int main() {
    
    
  pthread_t my_thread;
  int num = 42;
  int ret = pthread_create(&my_thread, NULL, thread_function, &num);
  if (ret != 0) {
    
    
    printf("Failed to create thread.\n");
    return -1;
  }
  printf("Thread created.\n");
  pthread_join(my_thread, NULL);
  printf("Thread joined.\n");
  return 0;
}
/*
执行结果:
Thread created.
Hello from thread! The number is 42.
Thread joined.
*/

スレッド同期 (mutex を使用)

#include <pthread.h>
#include <stdio.h>

int counter = 0;
pthread_mutex_t counter_mutex;

void *thread_function(void *arg) {
    
    
  int i; 
  for (i = 0; i < 1000000; i++) {
    
    
    pthread_mutex_lock(&counter_mutex);
    counter++;
    pthread_mutex_unlock(&counter_mutex);
  }
  pthread_exit(NULL);
}

int main() {
    
    
  pthread_t threads[4];
  pthread_mutex_init(&counter_mutex, NULL);
  int i; 
  for (i = 0; i < 4; i++) {
    
    
    pthread_create(&threads[i], NULL, thread_function, NULL);
  }
  for (i = 0; i < 4; i++) {
    
    
    pthread_join(threads[i], NULL);
  }
  pthread_mutex_destroy(&counter_mutex);
  printf("Counter value: %d\n", counter);
  return 0;
}
/*
执行结果:
Counter value: 4000000
*/

スレッド同期 (条件変数を使用)

#include <pthread.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>

bool flag = false;
pthread_mutex_t flag_mutex;
pthread_cond_t flag_cond;

void *thread_function(void *arg) {
    
    
  printf("Thread waiting for flag to be set...\n");
  pthread_mutex_lock(&flag_mutex);
  while (!flag) {
    
    
	printf("go thread here start...\n");
    pthread_cond_wait(&flag_cond, &flag_mutex);
	printf("go thread here end...\n");
  }
  pthread_mutex_unlock(&flag_mutex);
  printf("Flag has been set, thread exiting.\n");
  pthread_exit(NULL);
}

int main() {
    
    
  pthread_t my_thread;
  pthread_mutex_init(&flag_mutex, NULL);
  pthread_cond_init(&flag_cond, NULL);
  pthread_create(&my_thread, NULL, thread_function, NULL);
  sleep(1);
  printf("Setting flag to true...\n");
  pthread_mutex_lock(&flag_mutex);
  flag = true;
  printf("go main here start...\n");
  pthread_cond_signal(&flag_cond);
  printf("go main here mid...\n");
  pthread_mutex_unlock(&flag_mutex);
  printf("go main here end...\n");
  pthread_join(my_thread, NULL);
  pthread_mutex_destroy(&flag_mutex);
  pthread_cond_destroy(&flag_cond);
  return 0;
}
/*
执行结果:
Thread waiting for flag to be set...
go thread here start...
Setting flag to true...
go main here start...
go main here mid...
go main here end...
go thread here end...
Flag has been set, thread exiting.
*/

スレッド同期 (セマフォを使用)

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

#define BUFFER_SIZE 10

int buffer[BUFFER_SIZE];
int buffer_count = 0;

sem_t mutex; // 互斥信号量,保证 buffer_count 的原子性
sem_t empty; // 空信号量,表示 buffer 中空槽数量
sem_t full; // 满信号量,表示 buffer 中满槽数量

void* producer(void* arg) {
    
    
    int i, data;
    for (i = 0; i < 20; ++i) {
    
    
        data = rand() % 100;
        sem_wait(&empty); // 等待空槽
        sem_wait(&mutex); // 保证 buffer_count 的原子性
        buffer[buffer_count++] = data;
        printf("Produced: %d\n", data);
        sem_post(&mutex);
        sem_post(&full); // 释放一个满槽
        usleep(rand() % 100000); // 产生一定的延迟,模拟生产过程
    }
    return NULL;
}

void* consumer(void* arg) {
    
    
    int i, data;
    for (i = 0; i < 20; ++i) {
    
    
        sem_wait(&full); // 等待满槽
        sem_wait(&mutex); // 保证 buffer_count 的原子性
        data = buffer[--buffer_count];
        printf("Consumed: %d\n", data);
        sem_post(&mutex);
        sem_post(&empty); // 释放一个空槽
        usleep(rand() % 100000); // 消费过程中也产生一定的延迟
    }
    return NULL;
}

int main() {
    
    
    pthread_t producer_tid, consumer_tid;
    sem_init(&mutex, 0, 1); // 初始化互斥信号量为 1
    sem_init(&empty, 0, BUFFER_SIZE); // 初始化空信号量为 BUFFER_SIZE
    sem_init(&full, 0, 0); // 初始化满信号量为 0
    pthread_create(&producer_tid, NULL, producer, NULL);
    pthread_create(&consumer_tid, NULL, consumer, NULL);
    pthread_join(producer_tid, NULL);
    pthread_join(consumer_tid, NULL);
    sem_destroy(&mutex);
    sem_destroy(&empty);
    sem_destroy(&full);
    return 0;
}
/*
代码可能的执行结果:(里面用到rand(),回来的数是随机的)
Produced: 83
Consumed: 83
Produced: 15
Produced: 35
Consumed: 35
Consumed: 15
Produced: 21
Produced: 27
Consumed: 27
Consumed: 21
Produced: 26
Consumed: 26
Produced: 72
Consumed: 72
Produced: 68
Produced: 29
Consumed: 29
Consumed: 68
Produced: 23
Consumed: 23
Produced: 29
Consumed: 29
Produced: 58
Consumed: 58
Produced: 93
Produced: 11
Consumed: 11
Produced: 73
Consumed: 73
Produced: 84
Consumed: 84
Consumed: 93
Produced: 15
Produced: 13
Produced: 91
Consumed: 91
Consumed: 13
Produced: 62
Consumed: 62
Consumed: 15
*/

おすすめ

転載: blog.csdn.net/weixin_45767368/article/details/129279171