Linux Pthread Cond:掌握并发同步利器
linux pthread cond

首页 2024-12-12 19:44:41



Linux Pthread Cond:线程同步的得力助手 在Linux多线程编程中,线程间的同步和通信是一个至关重要的问题

    为了高效地协调多个线程对共享资源的访问,程序员需要依赖多种同步机制

    在这些机制中,条件变量(Condition Variables)以其独特的阻塞和唤醒功能,成为了实现线程同步的重要工具

    本文将深入探讨Linux中pthread条件变量的使用、原理及其相关函数,并通过具体示例展示其在实际编程中的应用

     条件变量的基本概念 条件变量是一种线程同步机制,它允许线程在某些条件不满足时进入阻塞状态,并在条件满足时被其他线程唤醒

    条件变量通常与互斥锁(Mutex)一起使用,以确保线程在访问共享资源时的安全性

    与互斥锁仅提供锁定和非锁定两种状态不同,条件变量提供了更丰富的线程控制手段,使得线程可以在条件不满足时等待,而不是忙等或轮询,从而提高了程序的效率和响应速度

     在Linux的pthread库中,条件变量的数据类型为`pthread_cond_t`

    使用条件变量前,需要先对其进行初始化,可以使用`pthread_cond_init`函数或宏`PTHREAD_COND_INITIALIZER`进行初始化

    初始化后的条件变量可以在线程间共享,用于实现线程间的同步和通信

     条件变量的相关函数 1.初始化与销毁 -`pthread_cond_init`:用于初始化一个条件变量

    其原型为`int pthread_cond_init(pthread_cond_tcond, const pthread_condattr_tcond_attr);

    其中,cond`是指向条件变量结构体的指针,`cond_attr`是指向条件变量属性结构体的指针

    如果`cond_attr`为NULL,则使用默认属性

     -`pthread_cond_destroy`:用于销毁一个条件变量

    其原型为`int pthread_cond_destroy(pthread_cond_tcond);`

    销毁后的条件变量不能再被使用

     2.等待与唤醒 -`pthread_cond_wait`:使线程阻塞在条件变量上,并自动解锁关联的互斥锁

    其原型为`int pthread_cond_wait(pthread_cond_tcond, pthread_mutex_t mutex);`

    线程在调用此函数后,会解锁`mutex`指向的互斥锁,并进入阻塞状态,等待条件变量`cond`被唤醒

    当线程被唤醒后,它会重新锁定`mutex`指向的互斥锁,并继续执行后续代码

     -`pthread_cond_signal`:用于唤醒一个阻塞在条件变量上的线程

    其原型为`int pthread_cond_signal(pthread_cond_tcond);`

    如果有多个线程阻塞在条件变量`cond`上,那么具体唤醒哪个线程是由线程的调度策略决定的

    需要注意的是,在使用`pthread_cond_signal`之前,必须确保已经锁定了保护条件变量的互斥锁,以防止条件满足信号在测试条件和调用`pthread_cond_wait`之间被发出,从而导致无限期的等待

     -`pthread_cond_broadcast`:用于唤醒所有阻塞在条件变量上的线程

    其原型为`int pthread_cond_broadcast(pthread_cond_tcond);`

    这个函数通常用于需要通知所有等待线程条件已经发生变化的场景

     3.定时等待 -`pthread_cond_timedwait`:与`pthread_cond_wait`类似,但增加了一个时间参数

    其原型为`int pthread_cond_timedwait(pthread_cond_t cond, pthread_mutex_t mutex, const structtimespec abstime);`

    在指定的绝对时间`abstime`到达之前,如果条件变量`cond`未被唤醒,则线程将解除阻塞并返回

    这个函数可以用于实现超时机制

     条件变量的使用示例 为了更好地理解条件变量的使用,下面通过一个简单的生产者-消费者模型来展示其在实际编程中的应用

     在这个示例中,生产者线程负责向缓冲区中写入数据,而消费者线程负责从缓冲区中读取数据

    为了保证线程间的同步和通信,我们使用了一个互斥锁来保护缓冲区的访问,并使用条件变量来通知消费者线程何时有数据可读或何时缓冲区已满

     include include include include defineBUFFER_SIZE 16 struct prodcons { intbuffer【BUFFER_SIZE】; pthread_mutex_t lock; pthread_cond_t notempty; pthread_cond_t notfull; int readpos, writepos; }; void init(struct prodconsb) { pthread_mutex_init(&b->lock, NULL); pthread_cond_init(&b->notempty,NULL); pthread_cond_init(&b->notfull,NULL); b->readpos = 0; b->writepos = 0; } void put(struct prodconsb, int data) { pthread_mutex_lock(&b->lock); // 等待缓冲区不满 while((b->writepos + 1) %BUFFER_SIZE == b->readpos) { pthread_cond_wait(&b->notfull, &b->lock); } // 向缓冲区中写入数据 b->buffer【b->writepos】 = data; b->writepos++; if(b->writepos >=BUFFER_SIZE){ b->writepos = 0; } // 通知缓冲区有数据可读 pthread_cond_signal(&b->notempty); pthread_mutex_unlock(&b->lock); } int get(struct prodconsb) { int data; pthread_mutex_lock(&b->lock); // 等待缓冲区有数据可读 while(b->writepos == b->readpos) { pthread_cond_wait(&b->notempty, &b->lock); } // 从缓冲区中读取数据 data = b->buffer【b->readpos】; b->readpos++; if(b->readpos >=BUFFER_SIZE){ b->readpos = 0; } // 通知缓冲区不满 pthread_cond_signal(&b->notfull); pthread_mutex_unlock(&b->lock); return data; } void producer(void arg) { struct pr