C互斥同步机制

在 C 语言中,常见的互斥同步工具和机制主要是基于 POSIX 标准,通常用于线程间的同步,保证在并发执行时共享资源的正确性。以下是常见的同步工具总结:

1. 互斥锁(Mutex)

互斥锁用于保护共享资源,确保在同一时刻只有一个线程可以访问共享资源。

  • 头文件#include <pthread.h>

初始化:

  • 使用 pthread_mutex_init() 初始化:

    1
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

    或者显式初始化:

    1
    2
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL);

常用操作:

  • 加锁:pthread_mutex_lock(&mutex);
    • 如果锁已经被其他线程占用,调用线程将被阻塞。
  • 尝试加锁(非阻塞):pthread_mutex_trylock(&mutex);
    • 如果锁被占用,立即返回错误代码。
  • 解锁:pthread_mutex_unlock(&mutex);
    • 释放锁,其他线程可以继续访问。

销毁:

  • pthread_mutex_destroy(&mutex);
    • 在不再使用时销毁互斥锁。

2. 读写锁(Read-Write Lock)

读写锁允许多个线程同时读取资源,但在写入资源时会阻塞其他线程的读写操作。

  • 头文件#include <pthread.h>

初始化:

  • 使用 pthread_rwlock_init() 初始化:

    1
    2
    pthread_rwlock_t rwlock;
    pthread_rwlock_init(&rwlock, NULL);

常用操作:

  • 读锁:pthread_rwlock_rdlock(&rwlock);
    • 允许多个线程同时获得读锁,但如果写锁被持有,读线程会被阻塞。
  • 写锁:pthread_rwlock_wrlock(&rwlock);
    • 只有一个线程可以获得写锁,且会阻塞所有读锁和写锁请求。
  • 释放读写锁:pthread_rwlock_unlock(&rwlock);
    • 释放当前持有的锁。

销毁:

  • pthread_rwlock_destroy(&rwlock);

3. 条件变量(Condition Variable)

条件变量用于在线程之间传递信号,常与互斥锁结合使用,用于实现线程等待与通知机制。

  • 头文件#include <pthread.h>

初始化:

  • 使用 pthread_cond_init() 初始化:

    1
    2
    pthread_cond_t cond;
    pthread_cond_init(&cond, NULL);

常用操作:

  • 等待条件:pthread_cond_wait(&cond, &mutex);
    • 等待某个条件发生,线程在此调用会释放互斥锁,直到被通知才重新获取锁。
  • 发送通知:pthread_cond_signal(&cond);
    • 通知一个正在等待的线程。
  • 广播通知:pthread_cond_broadcast(&cond);
    • 通知所有等待线程。

销毁:

  • pthread_cond_destroy(&cond);

4. 信号量(Semaphore)

信号量用于控制多个线程访问共享资源的数量,适用于限制并发数量。

  • 头文件#include <semaphore.h>

初始化:

  • 使用 sem_init() 初始化:

    1
    2
    sem_t sem;
    sem_init(&sem, 0, 1); // 第二个参数为0表示该信号量是线程间使用

常用操作:

  • 获取信号量:sem_wait(&sem);
    • 阻塞当前线程,直到信号量大于0,执行后信号量减1。
  • 释放信号量:sem_post(&sem);
    • 释放信号量,信号量加1。

销毁:

  • sem_destroy(&sem);

5. 自旋锁(Spinlock)

自旋锁是一种轻量级锁,适用于短时间内争用的场景,线程会在获取锁时持续自旋等待。

  • 头文件#include <pthread.h>

初始化:

  • 使用 pthread_spin_init() 初始化:

    1
    2
    pthread_spinlock_t spinlock;
    pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE);

常用操作:

  • 加锁:pthread_spin_lock(&spinlock);
    • 自旋等待获取锁。
  • 解锁:pthread_spin_unlock(&spinlock);
    • 释放锁。

销毁:

  • pthread_spin_destroy(&spinlock);

6. 屏障(Barrier)

屏障用于同步多个线程,在屏障处,线程必须等到所有线程到达后才会继续执行。

  • 头文件#include <pthread.h>

初始化:

  • 使用 pthread_barrier_init() 初始化:

    1
    2
    pthread_barrier_t barrier;
    pthread_barrier_init(&barrier, NULL, 3); // 3个线程需要在屏障点同步

常用操作:

  • 等待屏障:pthread_barrier_wait(&barrier);
    • 每个线程都会在此调用阻塞,直到所有线程都到达屏障点。

销毁:

  • pthread_barrier_destroy(&barrier);

总结

这些同步机制各自有不同的适用场景:

  • 互斥锁(Mutex):常用于保护共享资源,确保数据一致性。
  • 读写锁(Read-Write Lock):适合于读多写少的场景,可以提升读操作的并发性。
  • 条件变量(Condition Variable):用于线程间的通信和同步,解决生产者-消费者问题等。
  • 信号量(Semaphore):控制资源的并发访问,常用于限制并发线程的数量。
  • 自旋锁(Spinlock):适用于锁竞争非常短暂的情况。
  • 屏障(Barrier):用于多线程的同步,确保所有线程在某个点上同步执行。

这些工具的选择应根据实际需求来进行,既要考虑性能,也要保证数据的一致性和程序的正确性。