首页 > 编程知识 正文

两集合容斥原理公式极值,二值信号量和互斥信号量

时间:2023-05-06 18:59:32 阅读:110693 作者:2189

C互斥量mutex前言一、互斥量用法1.lock (,unlack )、2.lock_guard类模板3.unique_lock二、死锁三、lock函数模板四、总结

首先互斥量的存在是为了保护多线程中的数据安全。

一.互斥量用法1.lock (,unlack ) # include iostream # include list # include thread # includemutexusingnamespacestd; class a { public : voidm _ read () } { for (inti=1; i 100000; I () {m_mutex.lock ); Li.push_back(I; printf ('容器插入数据: %dn ),I ); m_mutex.unlock (; }}void m_write () for ) ) intI=1; i 100000; I () {m_mutex.lock ); if (! li.empty () ) {int s=li.front ); li.pop_front (; m_mutex.unlock (; }else{m_mutex.unlock (; printf('*****容器为空*******(n ) ); }}}private:mutex m_mutex; 李斯特利; (; int main () {A a; threadmyth1(a:3360m_read,a ); threadmyth2(a:3360m_write,a ); myth1.join (; myth2.join (; 返回0; }获取线程1 lock ()锁定(排他量)后,线程2将在该步骤中被阻塞,无法对数据a进行操作。 线程1 unlock ) )解除锁定时,线程2获得锁定并对数据a进行操作。 此时,线程1被阻止,无法对数据a进行操作。 也就是说,一个线程只能拥有一个锁,一个线程得到该锁后,其他线程会因为无法得到该锁而屏蔽等待。 得到锁的线程解除锁后,其他线程会试图取得锁,取得锁并成功后,其他线程会阻塞等待。

如果上述程序未锁定,则会有一定的概率报告错误。 出入操作不是一步完成的,在机器内部执行了多个步骤,因此如果插入多个步骤并在运行过程中切换到另一个线程,则容器不为空,但没有完整的数据,删除失败并报告错误。

注: lock ()、unlack () )需要进行解锁操作才能成为对。 特别是判断语句之前有解锁操作时,需要在不同条件的运行路径内进行解锁操作。

2.lock_guard类模板lock_guard类模板可以直接使用,而不是lock ()、unlack ()。 此外,使用lock_guard类模板后,不能在此保护区域中使用lock )、unlack )。

void m_read () { for } inti=1; i 100000; I ) lock_guardmutexm_guard(m_mutex ); Li.push_back(I; printf ('容器插入数据: %dn ),I ); } }当}} lock_guard类模板超出范围时,锁定将自动解除。

3.unique_lock unique_lock能够代替lock_guard而起到锁定和自动解除锁定的作用。

与lock_guard的独特性不同,unique_lock位于第二个参数的设置中

adopt_lock

角色:一个标志,指示unique_lock在构造函数中不需要名为lock的排他量。 作为前提,必须事先锁定排他量。 否则,会报告异常。 m_mutex.lock (; unique _ lockmutexm _ unique (m _ mutex,adopt_lock );//要保护的数据、try_to_lock

作用:试着拿钥匙。 获得锁时执行数据保护部分,未获得锁时执行其他部分。 这样,即使线程没有获得锁,也可以在不阻塞unique _ lockmutexm _ unique (m _ mutex,try_to_lock )的情况下等待。 获取if(m_unique.owns_lock () ) {printf ) )锁定并将数据插入容器(n ),); }else{printf ('由于未获得锁定,暂时无法插入数据n ); } defer_lock

角色:初始化未锁定互斥量unique_lock的成员函数

lock ()、unlock )、解锁; try_lock ),尝试锁定独占量,如果无法锁定,则返回false;如果无法锁定,则返回true。 此函数不会阻塞。 release (),返回它管理的lutext对象指针并释放所有权(也就是说,此unique_lock和mutext不再相关)。 二、死锁例如,有两个线程,各线程持有两个密钥a和b,线程1持有a密钥,想要持有b密钥,同时线程2持有b密钥,想要持有a密钥。 此时会形成死锁。 保持阻塞状态并等待,除非线程解除锁定。

class a { public : voidm _ read () } { for (inti=1; i 100000; I () m ) u

mutex.lock();y_mutex.lock();li.push_back(i);printf("容器插入数据:%dn", i);y_mutex.unlock();m_mutex.unlock();}}void m_write(){for (int i = 1; i < 100000; i++){y_mutex.lock();m_mutex.lock();if (!li.empty()){int s = li.front();li.pop_front();m_mutex.unlock();y_mutex.unlock();}else{m_mutex.unlock();y_mutex.unlock();printf("******容器为空******n");}}}private:mutex m_mutex;mutex y_mutex;list<int> li;};

  此设计就会形成死锁。

如何解决?
  使线程对锁的上锁顺序一致,就不会出现死锁。即线程1上锁顺序A、B;线程2上锁顺序A、B.


三、lock函数模板

  一次锁住两个或者两个以上的互斥量(至少两个,多了不限,1个不行);

  它不存在这种因为再多个线程中因为锁的顺序问题导致死锁的风险问题;

  std::lock():如果互斥量中有一个没锁住,它就在那里等着,等所有互斥量都锁住,它才能往下走(返回)﹔要么两个互斥量都锁住,要么两个互斥量都没锁住。如果只锁了一个,另外一个没锁成功,则它立即把已经锁住的解锁。

class A{public:void m_read(){for (int i = 1; i < 100000; i++){lock(m_mutex, y_mutex);li.push_back(i);printf("容器插入数据:%dn", i);y_mutex.unlock();m_mutex.unlock();}}void m_write(){for (int i = 1; i < 100000; i++){lock(m_mutex, y_mutex);if (!li.empty()){int s = li.front();li.pop_front();m_mutex.unlock();y_mutex.unlock();}else{m_mutex.unlock();y_mutex.unlock();printf("******容器为空******n");}}}private:mutex m_mutex;mutex y_mutex;list<int> li;};

  那可以不用手动unlock()? 可以,这需要与lock_guard类模板配合使用。

void m_read(){for (int i = 1; i < 100000; i++){lock(m_mutex, y_mutex);lock_guard<mutex> m_guard1(m_mutex, adopt_lock);lock_guard<mutex> m_guard2(y_mutex, adopt_lock);li.push_back(i);printf("容器插入数据:%dn", i);}}

  adopt_lock的作用就是在lock_guard m_guard1(m_mutex, adopt_lock);中对m_mutex不上锁,因为上面语句已经对其上锁了,不可再加锁。

四、总结

  虽然有多种锁,但是最好还是一个一个的锁,使用lock( )、unlack( )。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。