精华内容
下载资源
问答
  • 条件变量和互斥锁

    2021-01-06 17:20:00
    一直都有一个问题,就是条件变量为什么要和互斥锁一起使用,今天看了一篇文章,并结合APUE这本书,知道了其中的原因。 函数pthread_cond_wait()有几步操作:1。判断条件2.如果条件满足,继续执行;如果条件不满足,...

    1. 原文章:条件变量中互斥锁的作用

    一直都有一个问题,就是条件变量为什么要和互斥锁一起使用,今天看了一篇文章,并结合APUE这本书,知道了其中的原因。

    函数pthread_cond_wait()有几步操作:

    1. 判断条件,如果条件满足,继续执行;
    2. 如果条件不满足,就将线程挂到条件变量的等待线程队列中。

    如果不加锁的话,这两步之间就可能存在时间窗口,也就是(1)当线程1判断条件不满足,(2)然后准备把线程挂起的时候,线程2改变了条件,(3)接着线程1挂在了条件变量的等待队列上,这样就可能死锁。

    如果加上锁,这种时间窗口就会消除,使pthread_cond_wait的操作变成原子操作。pthread_cond_wait的第二个参数是一个加了锁的互斥量,这样可以避免线程在判断条件变量以及挂起的时候被别的线程改变条件。如果线程被挂起,pthread_cond_wait里面会解锁,是为了让别的线程来改变条件变量(别的线程在改变条件变量的时候,必须加锁,也是为了防止竞争)。但是从phread_cond_wait返回的时候,互斥量要再次被锁住。

    总的来说,互斥锁就是用来保护条件变量的,因为有一些操作不是原子操作,存在竞争。

    2. 条件变量

    条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(并给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。——百度百科

    3. 互斥锁

    锁的目的很明确,使线程们互斥地访问某个东西(变量、代码段)。它只有两个状态(被持有,未被持有)

    展开全文
  • Linux线程条件变量和互斥锁

    1. Linux线程条件变量

      条件变量是另一种逻辑比较复杂一点的线程同步互斥机制,它必须与互斥锁一起配合使用,它的应用场景也是很常见的,先来看一个例子
      小明、小华和小刚公用一张银行卡,每个人都可以从这张卡上取钱。银行卡余额很显然是一个由很多人共同操作的典型的共享资源,因此,任何人使用之前都需要加锁,在余额为0的情况下,需要进入某个条件变量等待队列中等待,在父母向这张卡上打钱之后,通知他们三个银行卡上有钱了,它们可以根据银行卡上的余额与自己的需求金额,进行取钱或者继续等待

    2. Linux线程条件变量函数接口

    初始化条件变量的函数原型:

    int pthread_cond_init(pthread_cond_t *cv, const pthread_condattr_t *a);

    cv 参数:条件变量

    a 参数:条件变量的属性,一般设置为NULL

    与其它同步互斥机制一样,条件变量在开始使用之前必须初始化,初始化函数中的属性一般设置为NULL即可。

    销毁条件变量的函数原型:

    int pthread_cond_destroy(pthread_cond_t *cv);

    cv 参数:条件变量

    当使用pthread_cond_destroy()销毁一个条件变量之后,它的值变得不确定,在使用时必须重新初始化

    进入条件变量等待队列的函数原型:

    int pthread_cond_wait (pthread_cond_t *cv, pthread_mutex_t *mutex);

    int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mutex, const struct timespec *t);

    cv 参数:条件变量

    mutex 参数:互斥锁

    t 参数:超时时间限制

    以上两个函数的功能是一样的,区别是pthread_cond_timedwait()函数可以设置超时时间

    唤醒条件变量等待的函数原型:

    int pthread_cond_broadcast (pthread_cond_t *cv);

    int pthread_cond_signal (pthread_cond_t *cv);

    cv 参数:条件变量

    a. 以上两个函数用来唤醒阻塞在条件变量等待队列中的线程,顾名思义,pthread_cond_broadcast用来唤醒全部线程,pthread_cond_signal只唤醒一个等待队列中的线程
    b. 注意,被唤醒的线程并不能立即从pthread_cond_wait()中返回,而是必须先获得配套的互斥锁

    3. Linux线程条件变量示例代码

    以下代码展示了小明、小华和小刚三个人如何取钱

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <pthread.h>
    #include <semaphore.h>
    
    int balancce = 0;       //共享资源:银行卡余额
    pthread_mutex_t m;      //互斥锁
    pthread_cond_t cond;    //条件变量
    
    void *routine(void *args){
        //加锁,取钱
        pthread_mutex_lock(&m);
        
        //如果余额不足,则进入条件等待队列
        while(balancce < 100){
            pthread_cond_wait(&cond, &m);
        }
        
        //如果余额充足,则进行取钱动作
        fprintf(stderr, "t%d: balance = %d\n", *(int *)args, balancce);
        balancce -= 100;
       
        //取完钱进行解锁动作
        pthread_mutex_unlock(&m);
        
        //退出线程
        pthread_exit(NULL);
    }
    
    int main(int argc, char**argv){
    
        //入参检查,比如传入要创建的线程数目
        if(argc < 2){
            printf("Usage: %s <thread_num> \n", argv[0]);
            return 1;
        }
    
        //互斥锁和条件变量进行初始化
        pthread_mutex_init(&m, NULL);
        pthread_cond_init(&cond, NULL);
    
        //循环创建若干条线程,这些线程执行取钱的动作
        pthread_t tid;
        int i;
        int thread_num = atoi(argv[1]);
        for(i = 0; i < thread_num; i++){
            pthread_create(&tid, NULL, routine, &i);
        }
    
        //接下来要往银行卡里打钱
        pthread_mutex_lock(&m);         //先加锁
        balancce += 100*thread_num;     //根据线程数打钱
        pthread_cond_broadcast(&cond);  //通知在条件变量等待队列中的线程
        pthread_mutex_unlock(&m);       //解锁
        
        //主线程退出
        pthread_exit(NULL);
    }
    

    在这里插入图片描述

    展开全文
  • 利用条件变量和互斥锁实现读写锁。 struct pthread_rwlock_t { pthread_mutex_t rw_mutex; //每一步获取读写锁,都要两次操作,上锁和解锁。每一步释放读写锁,也要两次操作,上锁和解锁。 pthread_cond_t rw_...
    
    //具体参阅:《Unix网络编程》卷2,进程间通信。利用条件变量和互斥锁实现读写锁。
    
    struct pthread_rwlock_t
    {
        pthread_mutex_t rw_mutex; //每一步获取读写锁,都要两次操作,上锁和解锁。每一步释放读写锁,也要两次操作,上锁和解锁。
        pthread_cond_t rw_condreaders;
        pthread_cond_t rw_condwritres;
        int rw_magic;
        int rw_nwaitreaders;//等待获取读锁的进程。
        int rw_nwaitwriters;//等待获取写锁的进程。
        int rw_refcount;//读写锁的当前状态,-1表示它是一个写入锁(任意时刻这样的锁只能有一个),为n(n>0)时,有n个进程正在同时读。
    };
    
    //以下是实现框架。大致思路日下:先判断当前状态rw_refcount和排队等待获取锁的waiters,再决定“获取锁”或者“加入等待,条件等待”.
    
    
    //获取读锁
    void pthread_rwlock_rdlock()
    {
        result=pthread_mutex_lock(&rw->rw_mutex);
    
        while(rw->rw_refcount<0||rw->rw_nwaitwriters>0){
            rw->rw_nwaitreaders++;
            result=pthread_cond_wait(&rw->rw_condreaders,&rw->rw_mutex);
            rw->rw_nwaitreaders--;
            if(result!=0)
                break;
        }
    
        if(result==0)
            rw->rw_refcount++;
    
         result=pthread_mutex_unlock(&rw->rw_mutex);
    }
    
    
    //获取写锁
    void pthread_rwlock_rdlock()
    {
        result=pthread_mutex_lock(&rw->rw_mutex);
    
        while(rw->rw_refcount!=0){
            rw->rw_nwaitwriters++;
            result=pthread_cond_wait(&rw->rw_condwritres,&rw->rw_mutex);
            rw->rw_nwaitwriters--;
            if(result!=0)
                break;
        }
    
        if(result==0)
            rw->rw_refcount=-1;
    
         result=pthread_mutex_unlock(&rw->rw_mutex);
    
    }
    
    
    //释放读写锁。用一个统一释放函数即可。
    void pthread_rwlock_rdlock()
    {
        result=pthread_mutex_lock(&rw->rw_mutex);
    
        if(rw->rw_refcount>0)
            rw->rw_refcount--;
        else if(rw->rw_refcount==-1)
            rw->rw_refcount=0;
        else 
            throw error; //在释放锁时rw->rw_refcount=0判断条件的出现是不可能的,因为一旦加锁,它只可能两种状态,-1和1,2,3....
        
        if(rw->rw_nwaitwriters>0)//为什么要先判断是否有等待写入者,因为如果有大量的读入者试图获取锁时,可能导致写入者永远无机会获取
            if(rw->rw_refcount==0)
                result=pthread_cond_signal(&rw->rw_condwritres);//一定要先给写入者机会,否则,写入者可能没机会获取锁。
        else if(rw->rw_nwaitreaders>0)
            result=pthread_cond_broadcast(&rw->rw_condreaders);
    
    
         result=pthread_mutex_unlock(&rw->rw_mutex);
    
    }
    

    展开全文
  • 用C++封装的跨平台条件变量和互斥量,windows环境和linux环境都测试好用, 是理解条件变量和互斥量的好demo。
  • 这篇文章主要说说线程同步的条件变量和互斥锁在线程中结合的使用,先看看几个概念 条件变量:是一种线程同步机制,条件变量允许线程睡眠,直到满足条件,当满足条件时,可以向该线程发信号,通知唤醒。 互斥锁: 互斥...

    这篇文章主要说说线程同步的条件变量和互斥锁在线程中结合的使用,先看看几个概念
    条件变量:是一种线程同步机制,条件变量允许线程睡眠,直到满足条件,当满足条件时,可以向该线程发信号,通知唤醒。
    互斥锁: 互斥锁用于控制多个线程对他们之间共享资源互斥访问的一个信号量。也就是说是为了避免多个线程在某一时刻同时操作一个共享资源。

    std::condition_variable 是为了解决死锁而生的。当互斥操作不够用而引入的。比如,线程可能需要等待某个条件为真才能继续执行,而一个忙等待循环中可能会导致所有其他线程都无法进入临界区使得条件为真时,就会发生死锁。所以,condition_variable实例被创建出现主要就是用于唤醒等待线程从而避免死锁。std::condition_variable的 notify_one()用于唤醒一个线程;notify_all() 则是通知所有线程。
    C++11中的std::condition_variable就像Linux下使用pthread_cond_wait和pthread_cond_signal一样,可以让线程休眠,直到别唤醒,现在在从新执行。线程等待在多线程编程中使用非常频繁,经常需要等待一些异步执行的条件的返回结果。

    为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起;通常情况下这个锁是std::mutex,并且管理这个锁 只能是 std::unique_lock<std::mutex> RAII模板类。

    条件满足一般使用
    等待条件成立使用的是condition_variable类成员wait 、wait_for 或 wait_until。给出信号使用的是condition_variable类成员notify_one或者notify_all函数

    在条件变量中只能使用std::unique_lockstd::mutex说明

    unique_lock和lock_guard都是管理锁的辅助类工具,都是RAII风格;它们是在定义时获得锁,在析构时释放锁。它们的主要区别在于unique_lock锁机制更加灵活,可以再需要的时候进行lock或者unlock调用,不非得是析构或者构造时。它们的区别可以通过成员函数就可以一目了然。

    在线程被阻塞时,该函数会自动调用 lck.unlock() 释放锁,使得其他被阻塞在锁竞争上的线程得以继续执行。另外,一旦当前线程获得通知(notified,通常是另外某个线程调用 notify_* 唤醒了当前线程),wait() 函数也是自动调用 lck.lock(),使得 lck 的状态和 wait 函数被调用时相同。

    //代码:
    std::mutex m_utex;
    std::queue<int> m_queue;
    std::condition_variable m_cv;
    
    BOOL bwhile = TRUE;
    void thread_read2(CMFCApplication7Dlg *pDlg)
    {
    	while (bwhile)
    	{
    		std::unique_lock<std::mutex> m_lock(m_utex);
    		
    		m_cv.wait(m_lock, [](){return !m_queue.empty(); });
    		if (bwhile == 0)
    		{
    			break;
    		}
    
    		int n = m_queue.front();
    		m_queue.pop();
    		m_lock.unlock();
    
    		CString strTmp = _T("");
    		strTmp.Format("thread_read2:%d", n);
    
    		SetDlgItemText(pDlg->m_hWnd, IDC_EDIT1, strTmp);
    
    		strTmp.Format("%d", m_queue.size());
    		SetDlgItemText(pDlg->m_hWnd, IDC_EDIT2, strTmp);
    		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    
    	}
    	return;
    }
    //开启读线程
    void CMFCApplication7Dlg::OnBnClickedButton1()
    {
    	// TODO:  在此添加控件通知处理程序代码
    
    	std::thread m_thread2(thread_read2, this);
    	m_thread2.detach();
    
    	GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);
    
    }
    //写数据
    int icount = 1;
    void CMFCApplication7Dlg::OnBnClickedButton2()
    {
    	// TODO:  在此添加控件通知处理程序代码
    	m_queue.push(icount++);
    	m_cv.notify_one();
    }
    

    结果:
    在这里插入图片描述
    在这里插入图片描述
    下面这篇文章讲解的不错:
    条件变量和互斥锁1
    条件变量和互斥锁2

    展开全文
  • Linux 线程条件变量和互斥锁开发实例代码执行结果 代码 main.c #include &amp;amp;amp;lt;stdio.h&amp;amp;amp;gt; #include &amp;amp;amp;lt;pthread.h&amp;amp;amp;gt; #include &amp;amp;amp...
  • 近期学习了线程等待和激活的相关...条件变量和互斥锁一样,都有静态动态两种创建方式, 静态方式使用PTHREAD_COND_INITIALIZER常量初始化。 pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 动态方式初始化:...
  • 1:写一个链表 2:如果超过固定大小push阻塞 3:如果链表为空,pop也会阻塞 直接看代码, main.cpp #include <stdio.h> #include <list> #include <iostream> #include <...publi...
  • C++条件变量和互斥锁

    2017-12-21 11:45:00
    3.为什么条件变量使用的互斥锁和PushEvent函数使用的互斥锁是同一个。 4.互斥锁到底保护了什么. 问题1:  为了更加有效的使用条件变量,我们使用了condition_variable::notify_all 来切换条件变量的状态...
  • 互斥锁1.什么叫互斥锁? 互斥锁(也成互斥量)可以用于保护关键代码段,以确保其独占式的访问,类似于二元信号量。二者都可以称为挂起等待锁———锁资源得不到满足,就会被挂起,在信号量或互斥锁上等待。注:当前...
  • 1.条件变量的作用 条件变量是利用线程...条件变量和信号量的区别 使用条件变量可以一次唤醒所有等待者,而这个信号量没有的功能 条件变量类似事件机制,当条件满足的时候会通知等待中的线程;而信号量没有这种通知机制
  • 最近在阅读《现代操作系统》,看到条件变量部分时非常疑惑条件变量为什么需要互斥锁,书上也没有非常明显解说原因(其实有说,但是我看书不仔细),查阅了一些资料,进行了一些思考。  我的疑惑点在于条件变量为...
  • 本文使用Linux系统调用,通过互斥锁和条件变量模拟生产者消费者问题。 #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> struct Node { int _val; ...
  • while (listHead == NULL) { //等待目标条件变量使得pthread_cond_wait操作的原子性 pthread_cond_wait(&need_product, &lock); } printf("call product:consum success and the value is %d\n", listHead->_...
  • 互斥锁 1.什么叫互斥锁? ​ 互斥锁(也成互斥量)可以用于保护关键代码段,以确保其独占式的访问,类似于二元信号量。二者都可以称为挂起等待锁———锁资源得不到满足,就会被挂起,在信号量或互斥锁上等待。 注:...
  • 1.什么叫互斥锁互斥锁(也成互斥量)可以用于保护关键代码段,以确保其独占式的访问,类似于二元信号量。二者都可以称为挂起等待锁———锁资源得不到满足,就会被挂起,在信号量或互斥锁上等待。 注:当前线程的...
  • //消费者的条件变量(既当满足这个条件时,消费者就可以进行相关的操作) public: Queue(int capacity = MAX_CAPACITY)//构造函数 将队列的总容量设为5 :_capacity(capacity) { pthread_mutex_init(&mutexs, NULL);...
  • 条件变量的执行过程(伪代码) int pthread_cond_wait(&amp;cond,&amp;wait) { int ret = pthread_cond_wait_and unlock(&amp;cond,&amp;wait);//进入阻塞状态后解锁 pthread_mutex_lock(&...
  • 条件变量和互斥锁去管理线程池

    千次阅读 2013-08-08 22:56:14
     在多个线程处理完大于线程数目的任务量时(一个线程一次处理一个任务),我们需要的就是资源的回收和善后操作,阻塞所有的线程,销毁线程池,销毁任务队列,销毁条件变量和互斥锁。 Void destory_thread_...
  • pthread_mutex_t: 互斥锁,多线程中对共享变量的包吧 pthread_cond_t

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,117
精华内容 846
关键字:

条件变量和互斥锁