2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
A thread is an execution unit in a process.
Responsible for the execution of the program in the current process,
There is at least one thread in a process
There can be multiple threads in a process
Multiple threads share all resources of the same process, and each thread participates in the unified scheduling of the operating system
It can be simply understood as process = memory resources + main thread + sub-thread +...
For tasks that are closely related, multithreading is preferred when running concurrently. For tasks that are not closely related and are relatively independent, multi-process is recommended.
The difference between threads and processes:
There are many commands in Linux system to view the process, including pidstat, top, ps, which can view the process or a
Threads under a process
Ubuntu needs to install the sysstat tool to support pidstat
sudo apt install sysstat
Options
-t: Display the threads associated with the specified process
-p : specify process pid
Example
View the threads associated with process 12345
sudo pidstat -t -p 12345
View all threads associated with a process
sudo pidstat -t
View the threads associated with process 12345, output once every 1 second
sudo pidstat -t -p 12345 1
View all threads associated with the process, output once every 1 second
sudo pidstat -t 1
The top command is used to view the threads under a process. You need to use the -H option in combination with -p to specify the pid.
Options
-H : Display thread information
-p : specify process pid
Example
View the threads associated with process 12345
sudo top -H -p 12345
View all threads associated with a process
sudo top -H
The ps command combined with the -T option can view all threads under a process
Options
-T : Display thread information
-p : specify process pid
Example
View the threads associated with process 12345
sudo ps -T -p 12345
View all threads associated with a process
sudo ps -T
In multi-process mode, each process is responsible for different tasks and does not interfere with each other. They run in different memory spaces and do not affect each other.
In multi-threaded mode, there can be multiple threads in a process, sharing the same memory space, and threads can communicate directly.
pthread_create() is used to create a thread. After successful creation, the thread starts running.
If the pthread_create() call is successful, it will return 0, otherwise it will return an error code.
Function header file:
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
Parameter Description:
return value:
Notice:
// 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() is used to exit the thread. After the thread is executed, it will automatically call pthread_exit() to exit.
Function header file:
#include <pthread.h>
void pthread_exit(void *retval);
Parameter Description:
pthread_join() is used to wait for the thread to end.
After calling pthread_join(), the current thread will be blocked until the thread ends.
Function header file:
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
Parameter Description:
return value:
// 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!
Threads are divided into joinable and detachable
// 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;
}
Other inter-process communications also apply to inter-thread communications.
When a child thread is created through the pthread_create() function, the fourth parameter of pthread_create() is the parameter passed to the function of the child thread.
When exiting a child thread through the pthread_exit() function, you can pass parameters to the main thread.
void pth_exit(void *retval);
Wait for the child thread to end through the pthread_join() function and get the return parameter of the child thread.
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;
}
A mutex is a synchronization mechanism used to control access to shared resources.
The main advantage of threads is the ability to share information through global variables, but this convenient sharing comes at a cost:
You must ensure that multiple threads do not modify the same variable at the same time
A thread will not read a variable that is being modified by another thread. In fact, two threads cannot access the critical section at the same time.
The principle of a mutex lock is that when a thread tries to enter a mutex area, if the mutex area is already occupied by other threads, the thread will be blocked until the mutex area is released.
Essentially a variable of type pthread_mutex_t, it contains an integer value that represents the state of the mutex.
When the value is 1, it means that the current critical resource can be accessed competitively, and the thread that obtains the mutex lock can enter the critical section. At this time, the value is 0, and other threads can only wait.
When the value is 0, it means that the current critical resource is occupied by other threads and cannot enter the critical area, so it can only wait.
typedef union
{
struct __pthread_mutex_s __data; // 互斥锁的结构体
char __size[__SIZEOF_PTHREAD_MUTEX_T];// 互斥锁的大小
long int __align;// 互斥锁的对齐
} pthread_mutex_t;
There are two main ways to initialize thread mutexes:
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER
Dynamic initialization Dynamic initialization mainly involves two functions: pthread_mutex_init function and pthread_mutex_destroy function
Used to initialize a mutex, it accepts two parameters: the address of the mutex and the attributes of the mutex.
Function header file:
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
Parameter Description:
return value:
Used to destroy a mutex, it accepts one parameter: the address of the mutex.
Function header file:
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
Parameter Description:
return value:
Example:
// 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;
}
Thread synchronization: refers to the orderly access of visitors to resources through other mechanisms based on mutual exclusion (in most cases).
Condition variables: A mechanism provided by the thread library specifically for thread synchronization
The typical application of thread synchronization is between producers and consumers.
In this model, there are producer threads and consumer threads, which are used to simulate the synchronization process of multiple threads.
In this model, the following components are required:
- Warehouse: used to store products, usually as a shared resource
- Producer thread: used to produce products
- Consumer thread: used for consumer products
principle:
When there is no product in the warehouse, the consumer thread needs to wait until there is a product before consuming
When the warehouse is full of products, the producer thread needs to wait until the consumer thread consumes the products.
Main thread is the consumer
n child threads as producers
// 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;
}
A condition variable is a synchronization mechanism that allows a thread to wait for a condition to be satisfied before continuing.
The principle of a condition variable is that it contains a mutex lock and a wait queue.
Mutexes are used to protect wait queues and condition variables.
The essence of the condition variable is pthread_cond_t type
其他线程可以阻塞在这个条件变量上, 或者唤
醒阻塞在这个条件变量上的线程
typedef union
{
struct __pthread_cond_s __data;
char __size[__SIZEOF_PTHREAD_COND_T];
__extension__ long long int __align;
} pthread_cond_t;
The initialization of conditional variables is divided into static initialization and dynamic initialization
To statically initialize a condition variable, you need to first define a variable of type pthread_cond_t and then initialize it to PTHREAD_COND_INITIALIZER.
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
To dynamically initialize a condition variable, you need to first define a variable of type pthread_cond_t and then call the pthread_cond_init function to initialize it.
Function header file:
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
Parameter Description:
return value:
Used to destroy the condition variable, it accepts one parameter: the address of the condition variable.
Function header file:
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
Parameter Description:
return value:
The use of condition variables is divided into waiting and notification
The waiting function pthread_cond_wait() accepts three parameters: the address of the condition variable, the address of the mutex lock, and the waiting time.
Function header file:
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
Parameter Description:
return value:
Notification Function
pthread_cond_signal() accepts one argument: the address of the condition variable.
Function header file:
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
Parameter Description:
return value:
Notify all functions
pthread_cond_broadcast() accepts one argument: the address of the condition variable.
Function header file:
#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond);
Parameter Description:
return value:
step 1 : 消费者线程判断消费条件是否满足 (仓库是否有产品),如果有产品可以消费,则可以正
常消费产品,然后解锁
step 2 : 当条件不能满足时 (仓库产品数量为 0),则调用 pthread_cond_wait 函数, 这个函数
具体做的事情如下:
在线程睡眠之前,对互斥锁解锁
让线程进⼊到睡眠状态
等待条件变量收到信号时 唤醒,该函数重新竞争锁,并获取锁后,函数返回
step 3 :重新判断条件是否满足, 如果不满足,则继续调用 pthread_cond_wait 函数
step 4 : 唤醒后,从 pthread_cond_wait 返回,消费条件满足,则正常消费产品
step 5 : 释放锁,整个过程结束
Why do condition variables need to be used in conjunction with mutexes?
Protecting shared data:
Mutex locks are used to protect shared data, ensuring that only one thread can access and modify the data at a time.
This avoids data races and inconsistency issues.
Condition variables are used for communication between threads to notify other threads that a certain condition has been met.
However, the operation of condition variables does not itself provide protection for shared data, so it needs to be used in conjunction with a mutex.
Avoid spurious wakeups:
One of the characteristics of condition variables is that spurious wakeups may occur.
That is, the thread is awakened without explicit notification. To avoid erroneous operations caused by this situation,
The thread needs to recheck whether the condition is actually met after waking up.
Using a mutex lock ensures that shared data is not modified by other threads while the condition is being checked, thus avoiding errors caused by spurious wakeups.
Ensure the correctness of the notification:
When a thread notifies other threads through a condition variable, it needs to ensure that the shared data has been updated before notifying.
A mutex lock can guarantee this, ensuring that all data updates are completed before releasing the lock.
Likewise, the thread receiving the notification needs to hold the mutex before checking the condition to ensure that the data is stable while checking the condition.
Implementing complex synchronization patterns:
Combining mutexes and condition variables can implement more complex synchronization patterns, such as producer-consumer problem, reader-writer problem, etc. Mutexes protect shared data, and condition variables are used for coordination and communication between threads.
// 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;
}