博客
关于我
【Linux】多线程---互斥锁,同步
阅读量:502 次
发布时间:2019-03-07

本文共 3466 字,大约阅读时间需要 11 分钟。

互斥与互斥锁的实现原理

在并发编程中,互斥是保证多个线程无法同时访问同一资源的关键机制。为了实现互斥,通常会采用互斥锁(Mutual Exclusion Lock, Mutual Lock)。

互斥锁本质上是一个同步机制,它通过确保只有一个线程能够在任何时刻占据整个资源的代码区域(临界区),从而防止资源竞争和数据 races。

互斥锁的内部实现

在互斥锁的内部,维护了一个计数器(Counter),也称为互斥量(Mutual Exclusion Degree)。这个计数器只有两种可能的值:

  • 0:表示当前没有线程持有互斥锁。
  • 1:表示当前有一个线程正在持有互斥锁。
  • 当线程试图获取互斥锁时,会检查计数器的值:

    • 如果计数器值为 0,表示没有其他线程持有互斥锁,此时当前线程可以获取互斥锁。
    • 如果计数器值为 1,则表示当前已经有一个线程持有互斥锁,此时当前线程无法获取互斥锁,必须等待。

    获取互斥锁属于原子操作,确保在修改计数器值时不会有其他线程观察到部分更新状态,避免可能的竞态条件。

    获取互斥锁的过程

    互斥锁的加锁过程分为三个步骤:

  • 检查寄存器中的值

    • 如果寄存器值为 1,表示当前可以加锁,直接将计数器值设置为 0,并通知线程开始访问临界区。
    • 如果寄存器值为 0,这表示有其他线程正在持有互斥锁,当前线程需要等待。
  • 交换寄存器与计数器的值

    这一步实际上是一个原子操作,确保在加锁时只允许一个线程成功获取互斥锁。

  • 返回加锁结果

    • 如果成功加锁(寄存器值为 1),返回成功标识,并修改计数器值。
    • 如果失败(寄存器值为 0),进入等待状态,直到计数器值变为 1
  • 互斥锁的加锁过程必须保证原子性,这意味着在获取互斥锁时,只能有一个线程能够成功加锁,避免数据竞争。

    互斥锁的接口与操作

    互斥锁的接口定义在 POSIX 标准中,主要包括以下几个函数:

    互斥锁的初始化

    // 静态互斥锁pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

    互斥锁的加锁函数

    // 阻塞加锁int pthread_mutex_lock(pthread_mutex_t *mutex);// 非阻塞加锁int pthread_mutex_trylock(pthread_mutex_t *mutex);// 带有超时时间的加锁int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abs_timeout);

    解锁函数

    int pthread_mutex_unlock(pthread_mutex_t *mutex);

    销毁互斥锁

    // 销毁互斥锁void pthread_mutex_destroy(pthread_mutex_t *mutex);

    条件变量与同步

    在多线程应用中,除了互斥锁外,还需要确保某些资源只有在特定条件满足时才能被访问。这个时候,条件变量(Condition Variable)发挥着重要作用。

    条件变量的作用

    条件变量通过维护一个等待队列和相关的唤醒操作,实现线程间的协调。即,当某个线程发现在某个条件不满足时(例如资源未准备就绪),它会将自身放入等待队列,等待其他线程的通知。当目标条件满足时,等待队列中的线程会被唤醒,继续执行任务。

    条件变量的接口

    条件变量的主要操作包括:

    • 初始化

      int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr);
    • 等待接口

      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);
    • 释放条件变量

      void pthread_cond_destroy(pthread_cond_t *cond);

    代码示例

    以下是一个使用互斥锁和条件变量的典型示例,它模拟了生产者和消费者对资源的互斥访问:

    #include 
    #include
    #include
    #define THREADCOUNT 2int g_bowl = 0;pthread_mutex_t g_mut;pthread_cond_t g_cond;void* MakeStart(void *arg) { while (1) { pthread_mutex_lock(&g_mut); while (g_bowl > 0) { pthread_cond_wait(&g_cond, &g_mut); } g_bowl++; printf("I am Make %p, g_bowl: %d\n", pthread_self(), g_bowl); pthread_mutex_unlock(&g_mut); pthread_cond_signal(&g_cond); } return NULL;}void* EatStart(void *arg) { while (1) { pthread_mutex_lock(&g_mut); while (g_bowl <= 0) { pthread_cond_wait(&g_cond, &g_mut); } g_bowl--; printf("I am Eat %p, g_bowl: %d\n", pthread_self(), g_bowl); pthread_mutex_unlock(&g_mut); pthread_cond_signal(&g_cond); } return NULL;}int main() { pthread_mutex_init(&g_mut, NULL); pthread_cond_init(&g_cond, NULL); pthread_t prod[THREADCOUNT], cons[THREADCOUNT]; for (int i = 0; i < THREADCOUNT; i++) { if (pthread_create(&prod[i], NULL, MakeStart, NULL) < 0) { perror("prod create error!\n"); return -1; } if (pthread_create(&cons[i], NULL, EatStart, NULL) < 0) { perror("cons create error!\n"); return -1; } } for (int i = 0; i < THREADCOUNT; i++) { pthread_join(prod[i], NULL); pthread_join(cons[i], NULL); } pthread_mutex_destroy(&g_mut); pthread_cond_destroy(&g_cond); return 0;}

    总结

    互斥锁是实现多线程安全的核心机制,它通过确保唯一的线程能够访问临界资源来避免竞态条件和数据 races。而条件变量则为线程间的协调提供了更高级的控制手段,特别是在资源仅在特定条件下可用时,条件变量能够有效地管理等待队列和唤醒过程。

    在实际应用中,互斥锁和条件变量通常结合使用,以实现更复杂的同步需求。通过合理使用这些机制,可以有效地构建高效且安全的多线程应用程序。

    转载地址:http://enacz.baihongyu.com/

    你可能感兴趣的文章
    常用元素操作的方法
    查看>>
    命名实体识别数据预处理
    查看>>
    分布式是登录机制是如何实现的。
    查看>>
    解决 matplotlib 中文显示乱码的问题
    查看>>
    解决打开 json 文件中文乱码的问题
    查看>>
    计算机网络基础:DHCP服务的部署
    查看>>
    计算机网络基础:DNS 部署与安全
    查看>>
    计算机网络基础:NAT 网络地址转换
    查看>>
    计算机网络基础:PKI(公钥基础设施)
    查看>>
    计算机网络基础:VLAN(虚拟局域网)
    查看>>
    计算机网络基础:文件共享服务器(注册表更改)
    查看>>
    计算机网络基础:用户和组管理
    查看>>
    计算机网络基础:简单渗透
    查看>>
    计算机网络模型-TCP/IP协议簇
    查看>>
    基于Arduino的ESP32-S3 + OLED(4pin)的文字取模
    查看>>
    基于Arduino的ESP32-S3 + 1.3寸OLED(4pin)
    查看>>
    基于Arduino的ESP32-S3连接OneNET云平台实战指南(二)——Token生成
    查看>>
    基于Arduino的ESP32-S3连接OneNET云平台实战指南(四)——ESP32-S3连接OneNET云平台的订阅主题与发布主题、消息(数据流)
    查看>>
    基于Arduino的ESP32-S3 + HCSR04(4pin)超声波传感器
    查看>>
    乒乓球问题
    查看>>