プライベートな連絡先の最初の情報
送料メール:
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
スレッドはプロセス内の実行単位です。
現在のプロセス内のプログラムの実行を担当します。
プロセス内に少なくとも 1 つのスレッドが存在する
プロセス内に複数のスレッドが存在する可能性があります
複数のスレッドが同じプロセスのすべてのリソースを共有し、各スレッドがオペレーティング システムの統合スケジューリングに参加します。
単純にプロセス = メモリ リソース + メイン スレッド + 子スレッド +… として理解できます。
密接に関連するタスクの場合は、同時実行中にマルチスレッドが優先されます。密接に関連せず、比較的独立したタスクの場合は、マルチプロセスを選択することをお勧めします。
スレッドとプロセスの違いは次のとおりです。
Linux システムには、pidstat、top、ps など、プロセスを表示するためのコマンドが多数あり、プロセスを表示したり、
処理中のスレッド
sysstat ツールを ubuntu にインストールする必要があると、pidstat をサポートできるようになります。
sudo apt インストール sysstat
オプション
-t: 指定したプロセスに関連付けられたスレッドを表示します。
-p: プロセス PID を指定します
例
プロセス 12345 に関連付けられたスレッドを表示する
sudo pidstat -t -p 12345
すべてのプロセスに関連付けられたスレッドを表示する
sudo pidstat -t
プロセス 12345 に関連付けられたスレッドを表示し、1 秒ごとに出力します
sudo pidstat -t -p 12345 1
すべてのプロセスに関連付けられたスレッドを表示し、1 秒ごとに出力します
sudo pidstat -t 1
特定のプロセスのスレッドを表示するには、top コマンドを使用します。pid を指定するには、-H オプションを -p と組み合わせて使用する必要があります。
オプション
-H: スレッド情報を表示します。
-p: プロセス PID を指定します
例
プロセス 12345 に関連付けられたスレッドを表示する
sudoトップ-H -p 12345
すべてのプロセスに関連付けられたスレッドを表示する
sudoトップ-H
ps コマンドと -T オプションを組み合わせて使用し、プロセス内のすべてのスレッドを表示します
オプション
-T: スレッド情報を表示します
-p: プロセス PID を指定します
例
プロセス 12345 に関連付けられたスレッドを表示する
sudo ps -T -p 12345
すべてのプロセスに関連付けられたスレッドを表示する
sudo ps -T
マルチプロセス モードでは、各プロセスは互いに干渉することなく、異なるタスクを担当します。各プロセスは、互いに影響を与えることなく、異なるメモリ空間で実行されます。
マルチスレッド モードでは、プロセス内に複数のスレッドが存在し、同じメモリ空間を共有することができ、スレッドは直接通信できます。
pthread_create() はスレッドの作成に使用され、作成が成功すると、スレッドの実行が開始されます。
pthread_create() が正常に呼び出されると、0 が返され、それ以外の場合はエラー コードが返されます。
関数ヘッダー ファイル:
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
パラメータの説明:
戻り値:
知らせ:
// todo : 创建一个线程,并在线程中打印出“Hello, World!”
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 线程函数
//@param arg 线程函数参数
void * print_hello(void *arg) {
printf("%sn",(char *)arg);
}
int main() {
pthread_t tid; //? typedef unsigned long int pthread_t;
// 创建线程
//@param tid 线程ID
//@param attr 线程属性
//@param start_routine 线程函数
//@param arg 线程函数参数
int ret = pthread_create(&tid, NULL,print_hello, "Hello, World!");
if (ret!= 0){
printf("pthread_create error!n");
return 1;
}
sleep(1); // 等待线程执行完毕
return 0;
}
pthread_exit() はスレッドを終了するために使用されます。スレッドの実行が完了すると、pthread_exit() が自動的に呼び出されて終了します。
関数ヘッダー ファイル:
#include <pthread.h>
void pthread_exit(void *retval);
パラメータの説明:
pthread_join() はスレッドが終了するのを待つために使用されます。
pthread_join() を呼び出した後、現在のスレッドはスレッドが終了するまでブロックされます。
関数ヘッダー ファイル:
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
パラメータの説明:
戻り値:
// todo : 创建一个线程,并在线程中打印出“Hello, World!”
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 线程函数
//@param arg 线程函数参数
void * print_hello(void *arg) {
sleep(1); // 休眠1秒
printf("%sn",(char *)arg);
pthread_exit(NULL); // 线程退出
}
int main() {
pthread_t tid; //? typedef unsigned long int pthread_t;
// 创建线程
//* @param tid 线程ID
//* @param attr 线程属性
//* @param start_routine 线程函数
//* @param arg 线程函数参数
int ret = pthread_create(&tid, NULL,print_hello, "Hello, World!");
if (ret!= 0){
printf("pthread_create error!n");
return 1;
}
printf("等待线程结束...n");
// 等待线程结束
//* @param thread 线程ID
//* @param status 线程退出状态
pthread_join(tid, NULL);
return 0;
}
等待线程结束...
Hello, World!
糸は結合可能と取り外し可能に分かれています
// todo : 创建一个线程,并在线程中打印出“Hello, World!”
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 线程函数
//@param arg 线程函数参数
void * print_hello(void *arg) {
sleep(1); // 休眠1秒
printf("%sn",(char *)arg);
pthread_exit(NULL); // 线程退出
}
int main() {
pthread_t tid; //? typedef unsigned long int pthread_t;
// 创建线程
//* @param tid 线程ID
//* @param attr 线程属性
//* @param start_routine 线程函数
//* @param arg 线程函数参数
int ret = pthread_create(&tid, NULL,print_hello, "Hello, World!");
if (ret!= 0){
printf("pthread_create error!n");
return 1;
}
printf("等待线程结束...n");
// 等待线程结束
//* @param thread 线程ID
//* @param status 线程退出状态
//pthread_join(tid, NULL);//! 阻塞等待线程结束,直到线程结束后才继续往下执行
//线程分离
pthread_detach(tid); //! 分离线程,不用等待线程结束后才退出程序,该线程的资源在它终止时由系统来释放。
printf("主线程结束n");
return 0;
}
// todo : 创建多个线程,执行不同的任务
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 线程函数
//@param arg 线程函数参数
void * print_hello_A(void *arg) {
sleep(1); // 休眠1秒
printf("%sn",(char *)arg);
pthread_exit(NULL); // 线程退出
}
// 线程函数
//@param arg 线程函数参数
void * print_hello_B(void *arg) {
sleep(2); // 休眠2秒
printf("%sn",(char *)arg);
pthread_exit(NULL); // 线程退出
}
int main() {
pthread_t tidA; //? 存储线程ID typedef unsigned long int pthread_t;
pthread_t tidB;
// 创建线程
//* @param tid 线程ID
//* @param attr 线程属性
//* @param start_routine 线程函数
//* @param arg 线程函数参数
int retA = pthread_create(&tidA, NULL,print_hello_A, "A_ Hello, World!");
if (retA!= 0){
printf("pthread_create error!n");
return 1;
}
int retB = pthread_create(&tidB, NULL,print_hello_B, "B_ Hello, World!");
if (retB!= 0){
printf("pthread_create error!n");
return 1;
}
printf("等待线程结束...n");
// 等待线程结束
//* @param thread 线程ID
//* @param status 线程退出状态
pthread_join(tidA, NULL);//! 阻塞等待线程结束,直到线程结束后才继续往下执行
pthread_join(tidB, NULL);
printf("主线程结束n");
return 0;
}
// todo : 创建多个线程,执行相同任务
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
//? 两个线程执行相同任务,对函数中的值修改了,会不会影响到其他线程的执行?
//! 在多线程编程中,如果多个线程执行相同的任务并且对共享资源进行修改,可能会影响到其他线程的执行。
//! 这是因为多个线程共享相同的内存空间,对共享资源的修改可能会导致竞态条件(race condition),
//! 从而导致不可预测的行为。
//! print_hello函数中的变量i是局部变量,每个线程都会有自己的i副本,因此对i的修改不会影响到其他线程。
//! 但是,如果涉及到共享资源(例如全局变量或静态变量),就需要考虑线程同步的问题,以避免竞态条件。
//*局部变量:每个线程都有自己的栈空间,因此局部变量是线程私有的,不会影响到其他线程。
//*共享资源:如果多个线程访问和修改同一个全局变量或静态变量,就需要使用同步机制(如互斥锁、信号量等)来确保线程安全。
//Linux:在Linux系统中,默认的线程栈大小通常是8MB。可以使用ulimit -s命令查看和修改当前用户的线程栈大小。例如,ulimit -s 1024将线程栈大小设置为1MB。
//Windows:在Windows系统中,默认的线程栈大小是1MB。可以通过编译器选项或在创建线程时指定栈大小来修改。
// 线程函数
//@param arg 线程函数参数
void * print_hello(void *arg) {
for (char i = 'a'; i < 'z' ; ++i) {
printf("%cn", i);
sleep(1); // 休眠1秒
}
pthread_exit(NULL); // 线程退出
}
int main() {
pthread_t tid[2]={0}; //? 存储线程ID的数组 typedef unsigned long int pthread_t;
for (int i = 0; i < 2; ++i) {
// 创建线程
//* @param tid 线程ID
//* @param attr 线程属性
//* @param start_routine 线程函数
//* @param arg 线程函数参数
int retA = pthread_create(&tid[i], NULL,print_hello, NULL);
if (retA!= 0){
printf("pthread_create error!n");
return 1;
}
}
printf("等待线程结束...n");
// 等待线程结束
//* @param thread 线程ID
//* @param status 线程退出状态
pthread_join(tid[0], NULL);//! 阻塞等待线程结束,直到线程结束后才继续往下执行
pthread_join(tid[1], NULL);
printf("主线程结束n");
return 0;
}
プロセス間のその他の通信は、スレッド間の通信にも当てはまります。
pthread_create() 関数を通じて子スレッドを作成する場合、pthread_create() の 4 番目のパラメーターは子スレッドの関数に渡されるパラメーターです。
pthread_exit() 関数を通じて子スレッドを終了するときに、メインスレッドにパラメータを渡すことができます。
void pth_exit(void *retval);
pthread_join()関数でサブスレッドの終了を待つ場合、サブスレッドの戻りパラメータを取得します。
int pthread_join (pthread_t __th, void **__thread_return);
//二级指针获取到了pthread_exit()函数参数指针的指向地址,通过该地址可以获取到子线程的返回参数。
// todo : 线程直接通讯,子线程向父线程传参
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 线程函数
//@param arg 线程函数参数
void * print_hello(void *arg) {
printf("子线程开始,结束之时传递参数100的地址n");
sleep(1); // 休眠1秒
//! int num=100;//局部变量,函数结束释放内存
static int num=100;//* 静态局部变量,函数结束不释放内存,延长生命周期
pthread_exit(&num); // 线程退出
}
int main() {
pthread_t tid; //? 存储线程ID typedef unsigned long int pthread_t;
// 创建线程
//* @param tid 线程ID
//* @param attr 线程属性
//* @param start_routine 线程函数
//* @param arg 线程函数参数
int retA = pthread_create(&tid, NULL,print_hello, NULL);
if (retA!= 0){
printf("pthread_create error!n");
return 1;
}
printf("等待线程结束...n");
void* num;//获取子进程传递的参数,num指向了子进程传递的参数
// 等待线程结束
//* @param thread 线程ID
//* @param status 线程退出状态
pthread_join(tid, (void **)&num);//! 阻塞等待线程结束,直到线程结束后才继续往下执行
printf("子线程结束,传递的参数为%dn",*(int*)num);
printf("主线程结束n");
return 0;
}
Mutex は、共有リソースへのアクセスを制御するために使用される同期メカニズムです。
スレッドの主な利点は、グローバル変数を通じて情報を共有できることですが、この便利な共有には代償が伴います。
複数のスレッドが同じ変数を同時に変更しないようにする必要があります。
実際、2 つのスレッドがクリティカル セクションに同時にアクセスすることはできません。
ミューテックス ロックの原理は、スレッドがミューテックス領域に入ろうとしたときに、そのミューテックス領域がすでに他のスレッドによって占有されている場合、そのスレッドはミューテックス領域が解放されるまでブロックされるというものです。
これは本質的に pthread_mutex_t 型の変数であり、ミューテックス領域のステータスを表す整数値が含まれます。
値が 1 の場合、現在のクリティカル リソースがアクセスを競合する可能性があり、ミューテックス ロックを取得したスレッドがクリティカル セクションに入ることができることを意味します。現時点では、値は 0 であり、他のスレッドは待機することしかできません。
値が 0 の場合、現在のクリティカル リソースが他のスレッドによって占有されており、クリティカル セクションに入ることができず、待機することしかできないことを意味します。
typedef union
{
struct __pthread_mutex_s __data; // 互斥锁的结构体
char __size[__SIZEOF_PTHREAD_MUTEX_T];// 互斥锁的大小
long int __align;// 互斥锁的对齐
} pthread_mutex_t;
スレッドのミューテックス ロックを初期化するには、主に 2 つの方法があります。
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER
動的初期化 動的初期化には、主に pthread_mutex_init 関数と pthread_mutex_destroy 関数の 2 つの関数が含まれます。
ミューテックス ロックを初期化するために使用され、ミューテックス ロックのアドレスとミューテックス ロックの属性という 2 つのパラメーターを受け入れます。
関数ヘッダー ファイル:
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
パラメータの説明:
戻り値:
ミューテックス ロックを破棄するために使用され、1 つのパラメータ (ミューテックス ロックのアドレス) を受け入れます。
関数ヘッダー ファイル:
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
パラメータの説明:
戻り値:
例:
// todo : 互斥锁;创建两个线程,分别对全局变量进⾏ +1 操作
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
static int global = 0;// 全局变量
//静态初始化互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;// 互斥锁
//动态初始化互斥锁
pthread_mutex_t mut;// 互斥锁
// 线程函数
//@param arg 线程函数参数
void * print_hello(void *arg) {
printf("子线程开始n");
int loops = *(int *)arg;
int i,tmp = 0;
for (i = 0;i < loops;i++){
pthread_mutex_lock(&mut);// 加锁
printf("子线程%d,global=%dn",i,global);
tmp = global;
tmp++;
global = tmp;
pthread_mutex_unlock(&mut);// 解锁
}
printf("子线程结束n");
pthread_exit(NULL); // 线程退出
}
int main() {
// 动态初始化互斥锁
//* @param mutex 互斥锁
//* @param attr 互斥锁属性 NULL 是默认属性
int r= pthread_mutex_init(&mut,NULL);
if (r!= 0){
printf("pthread_mutex_init error!n");
return 1;
}
pthread_t tid[2]={0}; //? 存储线程ID typedef unsigned long int pthread_t;
int arg=20;
for (int i = 0; i < 2; i++){
// 创建线程
//* @param tid 线程ID
//* @param attr 线程属性
//* @param start_routine 线程函数
//* @param arg 线程函数参数
int retA = pthread_create(&tid[i], NULL,print_hello, &arg);
if (retA!= 0){
printf("pthread_create error!n");
return 1;
}
}
printf("等待线程结束...n");
// 等待线程结束
//* @param thread 线程ID
//* @param status 线程退出状态
pthread_join(tid[0],NULL );//! 阻塞等待线程结束,直到线程结束后才继续往下执行
pthread_join(tid[1],NULL );
printf("%dn",global);
printf("主线程结束n");
// 销毁动态创建的互斥锁
//* @param mutex 互斥锁
pthread_mutex_destroy(&mut);// 销毁互斥锁
return 0;
}
スレッド同期: (ほとんどの場合) 相互排除に基づいて、訪問者による他のメカニズムを介したリソースへの秩序あるアクセスを指します。
条件変数: スレッド同期のためにスレッド ライブラリによって提供されるメカニズム。
スレッド同期の一般的なアプリケーション シナリオは、プロデューサーとコンシューマーの間で行われます。
このモデルでは、プロデューサー スレッドとコンシューマー スレッドに分割され、複数のスレッドの同期プロセスがこのスレッドを通じてシミュレートされます。
このモデルでは、次のコンポーネントが必要です。
- 倉庫: 通常、共有リソースとして製品を保管するために使用されます。
- プロデューサー スレッド: 製品の生産に使用されます
- コンシューマスレッド: 製品の消費に使用されます
原理:
倉庫に製品がない場合、コンシューマ スレッドは製品を消費できるようになるまで待つ必要があります。
倉庫が製品でいっぱいになると、プロデューサ スレッドはコンシューマ スレッドが製品を消費するまで待つ必要があります。
メインスレッドは消費者です
プロデューサとしての n 個のサブスレッド
// todo : 基于互斥锁实现⽣产者与消费者模型主线程为消费者,n 个⼦线程作为⽣产者
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
static int n = 0; // 产品数量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;// 互斥锁
//生产者执行函数
void * dofunc(void *arg) {
int arg1 = *(int*)arg;
for (int i = 0; i <arg1; i++) {
//获取互斥锁
pthread_mutex_lock(&mutex);
//生产产品
printf("生产者%ld生产了%d个产品n",pthread_self(),++n);//! pthread_self()返回当前线程ID
//释放互斥锁
pthread_mutex_unlock(&mutex);
//休眠1秒
sleep(1);
}
pthread_exit(NULL);
}
int main() {
pthread_t tid[4]={0}; //? 存储线程ID typedef unsigned long int pthread_t;
int arr[4]={1,2,3,4};
for (int i = 0; i < 4; i++) {
// 创建线程
//* @param tid 线程ID
//* @param attr 线程属性
//* @param start_routine 线程函数
//* @param arg 线程函数参数
int retA = pthread_create(&tid[i], NULL,dofunc,&arr[i] );
if (retA!= 0){
printf("pthread_create error!n");
return 1;
}
}
//消费者执行
for (int i = 0;i<10;i++) {
//获取互斥锁
pthread_mutex_lock(&mutex);
while (n > 0){
//消费产品
printf("消费者%ld消费了1个产品:%dn",pthread_self(),n--);
}
//释放互斥锁
pthread_mutex_unlock(&mutex);
//休眠1秒
sleep(1);
}
printf("等待线程结束...n");
// 等待线程结束
//* @param thread 线程ID
//* @param status 线程退出状态
pthread_join(tid[0],NULL );//! 阻塞等待线程结束,直到线程结束后才继续往下执行
pthread_join(tid[1],NULL );
pthread_join(tid[2],NULL );
pthread_join(tid[3],NULL );
return 0;
}
条件変数は、スレッドが実行を続行する前に特定の条件が満たされるまで待機できるようにする同期メカニズムです。
条件変数の原理は、条件変数にミューテックス ロックと待機キューが含まれていることです。
ミューテックス ロックは、待機キューと条件変数を保護するために使用されます。
条件変数の性質は pthread_cond_t 型です
其他线程可以阻塞在这个条件变量上, 或者唤
醒阻塞在这个条件变量上的线程
typedef union
{
struct __pthread_cond_s __data;
char __size[__SIZEOF_PTHREAD_COND_T];
__extension__ long long int __align;
} pthread_cond_t;
条件変数の初期化は、静的初期化と動的初期化に分けられます。
静的に初期化された条件変数の場合は、まず pthread_cond_t 型の変数を定義し、それから PTHREAD_COND_INITIALIZER に初期化する必要があります。
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
条件変数を動的に初期化するには、まず pthread_cond_t 型の変数を定義し、次に pthread_cond_init 関数を呼び出して初期化する必要があります。
関数ヘッダー ファイル:
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
パラメータの説明:
戻り値:
条件変数を破棄するために使用され、条件変数のアドレスという 1 つのパラメーターを受け取ります。
関数ヘッダー ファイル:
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
パラメータの説明:
戻り値:
条件変数の使用は待機と通知に分けられます
待機関数 pthread_cond_wait() は、条件変数のアドレス、ミューテックス ロックのアドレス、待機時間の 3 つのパラメータを受け取ります。
関数ヘッダー ファイル:
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
パラメータの説明:
戻り値:
通知機能
pthread_cond_signal() は、条件変数のアドレスという 1 つのパラメーターを受け入れます。
関数ヘッダー ファイル:
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
パラメータの説明:
戻り値:
すべての機能に通知
pthread_cond_broadcast() は、条件変数のアドレスという 1 つのパラメーターを受け入れます。
関数ヘッダー ファイル:
#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond);
パラメータの説明:
戻り値:
step 1 : 消费者线程判断消费条件是否满足 (仓库是否有产品),如果有产品可以消费,则可以正
常消费产品,然后解锁
step 2 : 当条件不能满足时 (仓库产品数量为 0),则调用 pthread_cond_wait 函数, 这个函数
具体做的事情如下:
在线程睡眠之前,对互斥锁解锁
让线程进⼊到睡眠状态
等待条件变量收到信号时 唤醒,该函数重新竞争锁,并获取锁后,函数返回
step 3 :重新判断条件是否满足, 如果不满足,则继续调用 pthread_cond_wait 函数
step 4 : 唤醒后,从 pthread_cond_wait 返回,消费条件满足,则正常消费产品
step 5 : 释放锁,整个过程结束
条件変数をミューテックス ロックと組み合わせて使用する必要があるのはなぜですか?
共有データを保護します。
ミューテックス ロックは、共有データを保護し、1 つのスレッドだけが同時にデータにアクセスして変更できるようにするために使用されます。
これにより、データの競合や不整合が回避されます。
条件変数は、スレッド間の通信に使用され、特定の条件が満たされたことを他のスレッドに通知します。
ただし、条件変数の操作自体は共有データの保護を提供しないため、ミューテックス ロックと組み合わせて使用する必要があります。
誤ったウェイクアップを回避します。
条件変数の特性の 1 つは、偽のウェイクアップが発生する可能性があることです。
つまり、スレッドは明示的な通知なしに起動されます。このような事態による誤操作を避けるため、
スレッドは、起動後に条件が実際に満たされているかどうかを再確認する必要があります。
ミューテックスを使用すると、条件のチェック中に共有データが他のスレッドによって変更されないことが保証されるため、偽のウェイクアップによって引き起こされるエラーが回避されます。
通知が正しいことを確認してください。
スレッドが条件変数を通じて他のスレッドに通知する場合、通知する前に共有データが更新されていることを確認する必要があります。
ミューテックスはこれを保証し、ロックを解放する前にすべてのデータ更新操作が完了していることを保証します。
同様に、通知を受信するスレッドは、条件をチェックするときにデータが安定していることを確認するために、条件をチェックする前にミューテックスを保持する必要があります。
複雑な同期パターンを実装します。
ミューテックス ロックと条件変数を組み合わせると、プロデューサーとコンシューマーの問題、リーダーとライターの問題など、より複雑な同期パターンを実装できます。ミューテックスは共有データを保護し、条件変数はスレッド間の調整と通信に使用されます。
// todo : 条件变量
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdlib.h>
static int number = 0;// 产品数量
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;// 互斥锁
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;// 条件变量
// 线程函数
//@param arg 线程函数参数
void * thread_handler(void *arg) {
int cnt = atoi((char *)arg);// 获取线程参数
int i,tmp;// 临时变量
for(i = 0;i < cnt;i++){// 生产产品
pthread_mutex_lock(&mtx);// 上锁
printf("线程 [%ld] ⽣产⼀个产品,产品数量为:%dn",pthread_self(),++number);
pthread_mutex_unlock(&mtx);// 解锁
//! 唤醒cond阻塞的线程
//! @param cond 条件变量
//pthread_cond_signal(&cond);//! 只能唤醒一个线程,如果有多个线程在等待,则只有一个线程会被唤醒
//唤醒所有线程
pthread_cond_broadcast(&cond);
}
pthread_exit((void *)0);// 线程退出
}
int main(int argc,char *argv[]) {
pthread_t tid[argc-1];// 线程ID
int i;
int err;
int total_of_produce = 0;// 总共生产的产品数量
int total_of_consume = 0;// 总共消费的产品数量
bool done = false;// 是否完成生产
//循环创建线程
for (i = 1;i < argc;i++){
total_of_produce += atoi(argv[i]);// 计算总共需要生产的产品数量
// 创建线程
err = pthread_create(&tid[i-1],NULL,thread_handler,(void *)argv[i]);
if (err != 0){
perror("[ERROR] pthread_create(): ");
exit(EXIT_FAILURE);
}
}
//消费者
for (;;){
//*先获取锁,再进行条件变量的等待
pthread_mutex_lock(&mtx);// 上锁
//*while循环来判断条件,避免虚假唤醒
while(number == 0) {// 等待生产者生产产品
//! 等待条件变量
//! @param cond 条件变量
//! @param mtx 互斥锁
//! 函数中会释放互斥锁,并阻塞线程,
//! 直到条件变量被唤醒,再重新竞争互斥锁,获取互斥锁并继续执行
pthread_cond_wait(&cond, &mtx);
}
while(number > 0){
total_of_consume++;// 总共消费的产品数量
printf("消费⼀个产品,产品数量为:%dn",--number);// 消费产品
done = total_of_consume >= total_of_produce;// 是否完成生产
}
pthread_mutex_unlock(&mtx);// 解锁
if (done)// 是否完成生产
break;
}
// 等待线程退出
for(i = 0;i < argc-1;i++){
pthread_join(tid[i],NULL);
}
return 0;
}
//循环创建线程
for (i = 1;i < argc;i++){
total_of_produce += atoi(argv[i]);// 计算总共需要生产的产品数量
// 创建线程
err = pthread_create(&tid[i-1],NULL,thread_handler,(void *)argv[i]);
if (err != 0){
perror("[ERROR] pthread_create(): ");
exit(EXIT_FAILURE);
}
}
//消费者
for (;;){
//*先获取锁,再进行条件变量的等待
pthread_mutex_lock(&mtx);// 上锁
//*while循环来判断条件,避免虚假唤醒
while(number == 0) {// 等待生产者生产产品
//! 等待条件变量
//! @param cond 条件变量
//! @param mtx 互斥锁
//! 函数中会释放互斥锁,并阻塞线程,
//! 直到条件变量被唤醒,再重新竞争互斥锁,获取互斥锁并继续执行
pthread_cond_wait(&cond, &mtx);
}
while(number > 0){
total_of_consume++;// 总共消费的产品数量
printf("消费⼀个产品,产品数量为:%dn",--number);// 消费产品
done = total_of_consume >= total_of_produce;// 是否完成生产
}
pthread_mutex_unlock(&mtx);// 解锁
if (done)// 是否完成生产
break;
}
// 等待线程退出
for(i = 0;i < argc-1;i++){
pthread_join(tid[i],NULL);
}
return 0;
}