C语言多线程编程-线程同步
2024-01-03 09:46:49
介绍
多线程编程,经常会遇到线程直接数据同步,为了保证数据访问安全,就必须考虑线程之间的同步问题。在C语言中,多线程编程的线程同步主要依赖于POSIX线程(Pthreads)库提供的同步原语。以下是一些关键的线程同步机制:
-
互斥锁 (Mutexes)
pthread_mutex_t
是一种互斥对象,用于保护共享资源,确保同一时间只有一个线程可以访问。
pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); // 初始化互斥锁 pthread_mutex_lock(&mutex); // 上锁 // 访问共享资源的代码 pthread_mutex_unlock(&mutex); // 解锁
-
读写锁 (Read-Write Locks)
pthread_rwlock_t
允许多个线程同时进行读取操作,但在写入操作时会排斥所有其他读写线程。
pthread_rwlock_t rwlock; pthread_rwlock_init(&rwlock, NULL); pthread_rwlock_rdlock(&rwlock); // 读取锁定 // 读取共享资源的代码 pthread_rwlock_unlock(&rwlock); // 释放锁定 pthread_rwlock_wrlock(&rwlock); // 写入锁定 // 更新共享资源的代码 pthread_rwlock_unlock(&rwlock); // 释放锁定
-
条件变量 (Condition Variables)
- 条件变量
pthread_cond_t
与互斥锁结合使用,允许线程阻塞等待特定条件变为真。
pthread_cond_t cond; pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond, NULL); pthread_mutex_lock(&mutex); while (!condition_is_true()) { // 检查条件 pthread_cond_wait(&cond, &mutex); // 条件不满足则等待 } // 当条件满足时执行相关操作 pthread_mutex_unlock(&mutex); // 另一个线程改变条件后,可以唤醒等待的线程 pthread_mutex_lock(&mutex); condition_make_true(); // 改变条件 pthread_cond_signal(&cond); // 唤醒一个等待线程 // 或者唤醒所有等待线程 pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mutex);
- 条件变量
-
信号量 (Semaphores)
- POSIX信号量
sem_t
也可以用于同步线程,它是一个计数器,控制可以同时访问资源的线程数量。
sem_t semaphore; sem_init(&semaphore, 0, 1); // 初始化为1,即一次只允许一个线程通过 sem_wait(&semaphore); // 阻塞直到信号量计数大于0并减一 // 执行临界区代码 sem_post(&semaphore); // 信号量加一,释放资源
- POSIX信号量
应用举例
以下是一个使用互斥锁(Mutexes)和条件变量(Condition Variables)实现的简单生产者-消费者问题的例子。生产者线程生成数据并放入缓冲区,消费者线程从缓冲区取出数据处理。
#include <pthread.h>
#include <stdio.h>
#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];
int buffer_count = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t full = PTHREAD_COND_INITIALIZER;
pthread_cond_t empty = PTHREAD_COND_INITIALIZER;
void* producer(void* arg) {
int i;
for (i = 0; i < 20; i++) {
pthread_mutex_lock(&mutex);
while (buffer_count == BUFFER_SIZE) { // 如果缓冲区已满
pthread_cond_wait(&full, &mutex); // 生产者等待
}
buffer[buffer_count++] = i; // 放入数据
printf("Producer produced %d\n", i);
pthread_cond_signal(&empty); // 唤醒消费者
pthread_mutex_unlock(&mutex);
}
return NULL;
}
void* consumer(void* arg) {
int i;
while (1) {
pthread_mutex_lock(&mutex);
while (buffer_count == 0) { // 如果缓冲区为空
pthread_cond_wait(&empty, &mutex); // 消费者等待
}
int data = buffer[--buffer_count]; // 取出数据
printf("Consumer consumed %d\n", data);
pthread_cond_signal(&full); // 唤醒生产者
pthread_mutex_unlock(&mutex);
// 在这里可以处理消费的数据,这里为了简化直接输出
}
return NULL;
}
int main() {
pthread_t producer_thread, consumer_thread;
pthread_create(&producer_thread, NULL, producer, NULL);
pthread_create(&consumer_thread, NULL, consumer, NULL);
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
pthread_cond_destroy(&full);
pthread_cond_destroy(&empty);
pthread_mutex_destroy(&mutex);
return 0;
}
示例说明
在这个例子中,创建了两个线程:一个生产者线程和一个消费者线程。生产者在缓冲区未满时产生数据,并通过条件变量full
通知消费者;消费者在缓冲区非空时消费数据,并通过条件变量empty
通知生产者。通过互斥锁mutex
保护对共享资源(缓冲区和缓冲区计数器)的访问,确保了线程间的同步。
总结
在使用这些同步机制时,重要的是要理解它们各自的适用场景和潜在的开销。不恰当的同步可能导致性能下降或死锁等问题。
文章来源:https://blog.csdn.net/scy518/article/details/135354388
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!