条件变量是线程间同步的等待/通知机制,用于在线程之间传递事件通知。它必须与互斥锁配合使用。
核心思想:一个线程等待某个条件成立,另一个线程在条件成立时发出通知。
#include <pthread.h>
// 动态初始化
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
// 静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// 销毁
int pthread_cond_destroy(pthread_cond_t *cond);
// 等待条件变量(原子释放锁+等待通知)
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
// 通知一个等待线程
int pthread_cond_signal(pthread_cond_t *cond);
// 通知所有等待线程
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_timedwait(pthread_cond_t *cond,
pthread_mutex_t *mutex,
const struct timespec *abstime);
pthread_cond_wait 的执行过程:
关键点:
错误使用示例:
// 错误:没有持有互斥锁
pthread_cond_wait(&cond, &mutex); // 未定义行为
// 错误:没有循环检查条件
pthread_mutex_lock(&mutex);
if (!condition) {
pthread_cond_wait(&cond, &mutex);
}
// 处理条件 // 可能虚假唤醒导致错误
pthread_mutex_unlock(&mutex);
正确使用模式:
pthread_mutex_lock(&mutex);
while (!condition) {
pthread_cond_wait(&cond, &mutex);
}
// 处理条件
pthread_mutex_unlock(&mutex);
条件变量可能在没有 signal 或 broadcast 的情况下唤醒线程,这是 POSIX 标准允许的行为。
使用 while 循环检查条件,而不是 if。
// 错误:可能虚假唤醒
if (count > 0) {
count--;
}
// 正确:循环检查
while (count <= 0) {
pthread_cond_wait(&cond, &mutex);
}
count--;
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#define BUFFER_SIZE 5
#define NUM_ITEMS 20
typedef struct {
int buffer[BUFFER_SIZE];
int in; // 生产者写入位置
int out; // 消费者读取位置
int count; // 当前缓冲区中的物品数量
pthread_mutex_t mutex;
pthread_cond_t not_full; // 缓冲区不满条件
pthread_cond_t not_empty; // 缓冲区不空条件
} BoundedBuffer;
void buffer_init(BoundedBuffer* buf) {
buf->in = 0;
buf->out = 0;
buf->count = 0;
pthread_mutex_init(&buf->mutex, NULL);
pthread_cond_init(&buf->not_full, NULL);
pthread_cond_init(&buf->not_empty, NULL);
}
void buffer_destroy(BoundedBuffer* buf) {
pthread_mutex_destroy(&buf->mutex);
pthread_cond_destroy(&buf->not_full);
pthread_cond_destroy(&buf->not_empty);
}
void buffer_produce(BoundedBuffer* buf, int item) {
pthread_mutex_lock(&buf->mutex);
// 等待缓冲区不满
while (buf->count >= BUFFER_SIZE) {
printf("Producer: buffer full, waiting...\n");
pthread_cond_wait(&buf->not_full, &buf->mutex);
}
// 生产物品
buf->buffer[buf->in] = item;
buf->in = (buf->in + 1) % BUFFER_SIZE;
buf->count++;
printf("Producer: produced %d, count: %d\n", item, buf->count);
// 通知消费者有数据
pthread_cond_signal(&buf->not_empty);
pthread_mutex_unlock(&buf->mutex);
}
int buffer_consume(BoundedBuffer* buf) {
pthread_mutex_lock(&buf->mutex);
// 等待缓冲区不空
while (buf->count <= 0) {
printf("Consumer: buffer empty, waiting...\n");
pthread_cond_wait(&buf->not_empty, &buf->mutex);
}
// 消费物品
int item = buf->buffer[buf->out];
buf->out = (buf->out + 1) % BUFFER_SIZE;
buf->count--;
printf("Consumer: consumed %d, count: %d\n", item, buf->count);
// 通知生产者有空间
pthread_cond_signal(&buf->not_full);
pthread_mutex_unlock(&buf->mutex);
return item;
}
void* producer(void* arg) {
BoundedBuffer* buf = (BoundedBuffer*)arg;
for (int i = 0; i < NUM_ITEMS; i++) {
buffer_produce(buf, i);
usleep(100000); // 100ms
}
return NULL;
}
void* consumer(void* arg) {
BoundedBuffer* buf = (BoundedBuffer*)arg;
for (int i = 0; i < NUM_ITEMS; i++) {
int item = buffer_consume(buf);
usleep(150000); // 150ms
}
return NULL;
}
int main() {
BoundedBuffer buf;
buffer_init(&buf);
pthread_t prod_thread, cons_thread;
pthread_create(&prod_thread, NULL, producer, &buf);
pthread_create(&cons_thread, NULL, consumer, &buf);
pthread_join(prod_thread, NULL);
pthread_join(cons_thread, NULL);
buffer_destroy(&buf);
return 0;
}
编译命令:
gcc -o bounded_buffer bounded_buffer.c -pthread
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#define NUM_EVENTS 10
typedef enum {
EVENT_TYPE_A,
EVENT_TYPE_B,
EVENT_TYPE_C,
EVENT_TYPE_EXIT
} EventType;
typedef struct {
EventType type;
int data;
} Event;
typedef struct {
Event events[NUM_EVENTS];
int head;
int tail;
int count;
pthread_mutex_t mutex;
pthread_cond_t event_available;
int running;
} EventQueue;
void queue_init(EventQueue* queue) {
queue->head = 0;
queue->tail = 0;
queue->count = 0;
queue->running = 1;
pthread_mutex_init(&queue->mutex, NULL);
pthread_cond_init(&queue->event_available, NULL);
}
void queue_destroy(EventQueue* queue) {
queue->running = 0;
pthread_cond_broadcast(&queue->event_available);
pthread_mutex_destroy(&queue->mutex);
pthread_cond_destroy(&queue->event_available);
}
int queue_push(EventQueue* queue, Event* event) {
pthread_mutex_lock(&queue->mutex);
if (queue->count >= NUM_EVENTS) {
pthread_mutex_unlock(&queue->mutex);
return -1;
}
queue->events[queue->tail] = *event;
queue->tail = (queue->tail + 1) % NUM_EVENTS;
queue->count++;
pthread_cond_signal(&queue->event_available);
pthread_mutex_unlock(&queue->mutex);
return 0;
}
int queue_pop(EventQueue* queue, Event* event) {
pthread_mutex_lock(&queue->mutex);
while (queue->count == 0 && queue->running) {
pthread_cond_wait(&queue->event_available, &queue->mutex);
}
if (!queue->running && queue->count == 0) {
pthread_mutex_unlock(&queue->mutex);
return -1;
}
*event = queue->events[queue->head];
queue->head = (queue->head + 1) % NUM_EVENTS;
queue->count--;
pthread_mutex_unlock(&queue->mutex);
return 0;
}
void* event_handler(void* arg) {
EventQueue* queue = (EventQueue*)arg;
Event event;
while (queue_pop(queue, &event) == 0) {
switch (event.type) {
case EVENT_TYPE_A:
printf("Handler: Event A with data %d\n", event.data);
break;
case EVENT_TYPE_B:
printf("Handler: Event B with data %d\n", event.data);
break;
case EVENT_TYPE_C:
printf("Handler: Event C with data %d\n", event.data);
break;
case EVENT_TYPE_EXIT:
printf("Handler: Exit event received\n");
return NULL;
default:
printf("Handler: Unknown event type\n");
}
}
return NULL;
}
void* event_generator(void* arg) {
EventQueue* queue = (EventQueue*)arg;
Event event;
for (int i = 0; i < 5; i++) {
event.type = EVENT_TYPE_A;
event.data = i;
queue_push(queue, &event);
usleep(100000);
event.type = EVENT_TYPE_B;
event.data = i * 10;
queue_push(queue, &event);
usleep(100000);
}
// 发送退出事件
event.type = EVENT_TYPE_EXIT;
queue_push(queue, &event);
return NULL;
}
int main() {
EventQueue queue;
queue_init(&queue);
pthread_t handler_thread, generator_thread;
pthread_create(&handler_thread, NULL, event_handler, &queue);
pthread_create(&generator_thread, NULL, event_generator, &queue);
pthread_join(generator_thread, NULL);
pthread_join(handler_thread, NULL);
queue_destroy(&queue);
return 0;
}
编译命令:
gcc -o event_queue event_queue.c -pthread
while 循环检查条件signal 可能丢失,需要确保条件被检查A:
pthread_cond_signal 和 pthread_cond_broadcast 的区别?A:
signal:唤醒一个等待线程broadcast:唤醒所有等待线程A:
while 循环检查条件A:
while 循环确保条件被检查A: