C语言多线程编程-线程同步

介绍

多线程编程,经常会遇到线程直接数据同步,为了保证数据访问安全,就必须考虑线程之间的同步问题。在C语言中,多线程编程的线程同步主要依赖于POSIX线程(Pthreads)库提供的同步原语。以下是一些关键的线程同步机制:

  1. 互斥锁 (Mutexes)

    • pthread_mutex_t 是一种互斥对象,用于保护共享资源,确保同一时间只有一个线程可以访问。
    c 复制代码
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL); // 初始化互斥锁
    pthread_mutex_lock(&mutex);       // 上锁
    // 访问共享资源的代码
    pthread_mutex_unlock(&mutex);     // 解锁
  2. 读写锁 (Read-Write Locks)

    • pthread_rwlock_t 允许多个线程同时进行读取操作,但在写入操作时会排斥所有其他读写线程。
    c 复制代码
    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);  // 释放锁定
  3. 条件变量 (Condition Variables)

    • 条件变量 pthread_cond_t 与互斥锁结合使用,允许线程阻塞等待特定条件变为真。
    c 复制代码
    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);
  4. 信号量 (Semaphores)

    • POSIX信号量 sem_t 也可以用于同步线程,它是一个计数器,控制可以同时访问资源的线程数量。
    c 复制代码
    sem_t semaphore;
    sem_init(&semaphore, 0, 1); // 初始化为1,即一次只允许一个线程通过
    
    sem_wait(&semaphore); // 阻塞直到信号量计数大于0并减一
    // 执行临界区代码
    sem_post(&semaphore); // 信号量加一,释放资源

应用举例

以下是一个使用互斥锁(Mutexes)和条件变量(Condition Variables)实现的简单生产者-消费者问题的例子。生产者线程生成数据并放入缓冲区,消费者线程从缓冲区取出数据处理。

c 复制代码
#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保护对共享资源(缓冲区和缓冲区计数器)的访问,确保了线程间的同步。

总结

在使用这些同步机制时,重要的是要理解它们各自的适用场景和潜在的开销。不恰当的同步可能导致性能下降或死锁等问题。

相关推荐
luj_17681 分钟前
心形曲线轨迹控制三大关键技术
c语言·开发语言·c++·经验分享·算法
tmlx3I08126 分钟前
高光谱拼接算法(六)RANSAC 误匹配剔除
人工智能·算法·机器学习
不相心 -w-35 分钟前
基础-滑动窗口-(定长 | 不定长)
算法
醉城夜风~1 小时前
Java详解经典算法题:接雨水(三种实现方案+原理剖析)
java·开发语言·算法
ysa0510301 小时前
【板子】ST表
c++·笔记·算法·板子
CHHH_HHH2 小时前
【C++11】深入解析C++可变参数模板
开发语言·c++·算法·stl·c++11
hurrycry_小亦2 小时前
洛谷题目:P1215 [USACO1.4] 母亲的牛奶 Mother‘s Milk 题解(本题简)
算法
KJ_BioMed3 小时前
从PDB到高亲和力分子:De novo生成式计算化学Pipeline剖析
算法·生物医药·生物科研·科研干货·化合物设计
一个王同学3 小时前
从零到一 | CV转多模态大模型 | week17 | LLM 推理优化 & vLLM 详解
人工智能·深度学习·算法·机器学习·计算机视觉·vllm
jimy14 小时前
C语言模拟对象、方法:“函数指针+结构体“复用函数指针指向的函数体
c语言·开发语言