多线程之互斥锁、条件变量

多线程

一个进程在同一时刻只能做一件事,而多个线程却可以同时执行,每个线程处理各自独立的任务。多线程有很多好处:

  • 简化处理异步事件的代码
  • 实现内存和文件描述符的共享
  • 改善程序的吞吐量
  • 改善响应时间

互斥锁

互斥锁:互斥锁通过锁机制来实现线程间的同步,在同一时刻通常只允许一个关键部分的代码

当多个线程控制相同的内存时,对于读写操作的时间差距就有可能会导致数据的不同步,下图就很清晰的说明了这种情况:

对于线程A、B此时对同一块内存进行操作,但是由于操作几乎是同时进行的,假设当线程A读入数据i之后,在对数据 i 自加1的同时线程B将原来内存中的数据 i 读出,然后线程A将自加后的数据再写入内存中,同时线程B对读取到的 i 加1,最后将其写入内存,这个程序原本是想通过两个线程对变量 i 进行两次自加运算最后预想的结果应当是7,最后却得到异常的结果。对于这种临界变量操作时就有可能导致意外的结果,因而出现了互斥锁和条件变量来保证数据只被一个线程操作。

下面程序的运行结果也很好的说明了多线程操作同一变量不稳定性:

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<errno.h>

int a = 0;      //用作要改变的全局变量
pthread_mutex_t mutex;  //互斥锁变量

void thread1(void *arg)
{
    //pthread_mutex_lock (&mutex); //加锁
    printf("thread1 a = %d\n", a);
    a++;
    //pthread_mutex_unlock (&mutex);
}

void thread2(void *arg)
{
    //pthread_mutex_lock (&mutex);
    printf("thread2 a = %d\n", a);
    a++;
    //pthread_mutex_unlock (&mutex);
}

void thread3(void *arg)
{
    //pthread_mutex_lock (&mutex);
    printf("thread3 a = %d\n", a);
    a++;
    //pthread_mutex_unlock (&mutex);
}

int main(void)
{
    pthread_t tid1, tid2, tid3;   //用于接收线程ID
    int       err;                //出错码
    void *    tret;               //返回值

    //创建三个线程
    pthread_create (&tid1, NULL, (void *)thread1, NULL);
    pthread_create (&tid2, NULL, (void *)thread2, NULL);
    pthread_create (&tid3, NULL, (void *)thread3, NULL);

    //等待辅线程结束
    err = pthread_join(tid1, &tret);
    if(err != 0)
    {
        perror("join");
    }
    err = pthread_join(tid2, &tret);
    if(err != 0)
    {
        perror("join");
    }
    err = pthread_join(tid3, &tret);
    if(err != 0)
    {
        perror("join");
    }

    printf("result a: %d\n", a);   //查看最后的结果
    exit(0);
}

多次执行结果如下:

发现几次的执行结果并不相同,本来程序是通过三个线程对同一个全局变量进行3次加1的操作结果应当为0, 1,2,3,由于线程间数据不同步所以导致了这样的结果。

当前我们将程序中各个thread函数中的注释取消之后就会得到这样的结果:

这里就体现了互斥锁来保证线程间数据的同步。

使用互斥锁应当注意:

  1. 使用之前必须进行初始化
  2. 加锁时,若锁变量已经被锁住,则当前尝试加锁的线程就会阻塞,直到互斥锁被其他线程释放
  3. 调用解锁函数的线程必须是给互斥锁加锁的线程
  4. 当一个线程试图以另一个线程相反的顺序锁住互斥量的时候,就有可能出现死锁
  5. 如果线程试图对一个互斥量加锁两次,那么它自身就会陷入死锁状态

死锁:指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程

条件变量

条件变量:是利用线程间共享的全局变量进行同步的一种机制

使用条件变量要注意:

  1. 使用之前要初始化
  2. 条件变量通常是在互斥锁的保护下求值,若条件表达式为假,那么线程基于条件变量阻塞。
  3. 线程被条件变量阻塞后,可以通过pthread_cond_signal和pthread_cond_broadcast激活,pthread_cond_signal激活按照入队顺序激活一个等待线程,pthread_cond_broadcast则激活所有的等待线程
  4. 当一个条件变量不再使用时,需要将其清除,清除函数:pthread_cond_destory,只有在没有线程等待该条件变量的时候才能清除这个条件变量,否则返回EBUSY。
  5. 调用pthread_cond_wait()前必须有本线程加锁,防止多个线程同时请求pthread_cond_wait()。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-09 17:37:20

多线程之互斥锁、条件变量的相关文章

关于互斥锁,条件变量的内核源码解析

一.解决问题和适用范围 主要是用来等待一个条件,这个条件可能需要另一个线程来满足这个条件.这个和我们平常适用的pthread_mutex_lock的最大不同在于后者保护的一般是一个代码段(也就是关键区),或者一个变量,但是由于一般来说这个变量的访问是在一个关键区中,所以可以认为是一个关键区. 但是对于条件变量,是需要的是一个事件,只有事件满足的时候才会执行后面的操作,此时就出现一个问题:如果不满足我们应该怎么办?如果如果使用简单信号量,可能另一方触发了这个条件,然后通过unlock来唤醒一个线程

转载~kxcfzyk:Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解

Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解 多线程c语言linuxsemaphore条件变量 (本文的读者定位是了解Pthread常用多线程API和Pthread互斥锁,但是对条件变量完全不知道或者不完全了解的人群.如果您对这些都没什么概念,可能需要先了解一些基础知识) 关于条件变量典型的实际应用,可以参考非常精简的Linux线程池实现(一)——使用互斥锁和条件变量,但如果对条件变量不熟悉最好先看完本文. Pthread库的条件变量机制的主要API有三个: int p

多个生产者——多个消费者模型(互斥量条件变量实现)

1. 介绍 生产者消费者问题属于有界缓冲区问题.我们现在讲述多个生产者向一个缓冲区中存入数据,多个生产者从缓冲区中取数据. 共享缓冲区作为一个环绕缓冲区,存数据到头时再从头开始. 2. 实现 我们使用一个互斥量保护生产者向缓冲区中存入数据. 由于有多个生产者,因此需要记住现在向缓冲区中存入的位置. 使用一个互斥量保护缓冲区中消息的数目,这个生产的数据数目作为生产者和消费者沟通的桥梁. 使用一个条件变量用于唤醒消费者.由于有多个消费者,同样消费者也需要记住每次取的位置. 4.代码 在选项中选择生产

Linux多线程编程-互斥锁

互斥锁 多线程编程中,(多线程编程)可以用互斥锁(也称互斥量)可以用来保护关键代码段,以确保其独占式的访问,这有点像二进制信号量.POSIX互斥锁相关函数主要有以下5个: #include <pthread.h> int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); int pthread_mutex_destroy(pthread_mutex_t *mutex); int p

互斥和条件变量区别

互斥量(mutex)从本质上说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁.对互斥量进行加锁以后,任何其他试图再次对互斥锁加锁的线程将会阻塞直到当前线程释放该互斥锁.如果释放互斥锁时有多个线程阻塞,所有在该互斥锁上的阻塞线程都会变成可运行状态,第一个变为运行状态的线程可以对互斥锁加锁,其他线程将会看到互斥锁依然被锁住,只能回去再次等待它重新变为可用. 条件变量(cond)是在多线程程序中用来实现"等待–>唤醒"逻辑常用的方法.条件变量利用线程间共享的全

Linux多线程实践(8) --Posix条件变量解决生产者消费者问题

Posix条件变量 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); int pthread_cond_destroy(pthread_cond_t *cond); int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_timedwait(pthread_cond_t *cond

Linux互斥量&amp;条件变量

互斥量 Mutex 互斥量1. #include <pthread.h>  2. int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);  3.   4. int pthread_mutex_lock(pthread_mutex_t *mutex);  5.   6. int pthread_mutex_unlock(pthread_mutex_t *mutex);  7.   

线程同步与互斥之条件·变量

条件变量(condition variable) 线程间的同步与互斥技术,主要以互斥锁和条件变量为主,条件变量和互斥所的配合使用可以很好的处理对于条件等待的线程间的同步问题.举个例子:消费者和生产者问题. 消费者与生产者最基本的关系是服务与被服务的关系,但是在线程同步与互斥中强调的是两者访问资源的关系.首先生产与消费的关系为:同步与互斥,生产与生产的关系为:互斥,消费与消费的关系为:互斥.所以维护这三种关系的有两类人:生产者与消费者.并且生产数据与消费数据必须有场所. 所以将其简述为三种关系两类

多线程与互斥锁

线程:线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针.程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数. 多线程:多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务. 线程创建 函数原型:int pthread_create(pthread_t*restrict tidp,const pthread_attr_t *restrict attr,void *(*star