多线程第七篇:互斥和同步总结

2024-08-24 16:18

本文主要是介绍多线程第七篇:互斥和同步总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

   同步:多个线程(进程)之间有严格的先后顺序,一个线程(进程)的执行,依赖于另一个.
   互斥:多个线程(进程)没有先后顺序,谁抢到算谁的.
 

注意:线程的创建和执行是分开的,并不是创建后立即执行,而是创建后,等待cpu调度.

window中的四种线程(进程)间同步与互斥.
criticalSection,mutex,event,semaphore

criticalSection:
     1.中文名称临界区或者关键段,用于线程间互斥.
     2.进入和离开必须成对出现.
     3.不是内核对象,不能用于进程间互斥,只能用于线程间互斥
     4.由于不是内核级对象,所以速度较快,效率较高.
使用:
     1.InitializeCriticalSection
     2.EnterCriticalSection
     3.LeaveCriticalSection
注意事项:
     临界区为子线程所有,主线程中使用临界区并不能实现互斥.


mutex:
     1.互斥区,用于线程(进程)间互斥
     2.记录拥有着,可以处理遗弃问题,当前使用该互斥区的线程(进程)占有该互斥区,并且,其他线程(进程)不能使用.
     3.可以在线程A中waitforsignalobject,在线程B中release.
     4.是内核对象,可以进行进程间互斥.
使用:
     1.CreateMutex或者OpenMutex
     2.ReleaseMutex 
     3.WaitForSingleObject
     4.CloseHandle
event:
     1.事件,用于线程(进程)间同步和互斥.
     2.是内核对象,不具有拥有权,即可以由一个线程(进程)触发,而由另一个线程(进程)恢复.
使用:
     1.CreateEvent
     2.SetEvent
     3.ResetEvent
     4.PulseEvent
     5.WaitForSingleObject
     6.CloseHandle

semaphore:
     1.信号量,用于线程(进程)间同步和互斥.
     2.是内核对象,不具有拥有权,可以在不同的线程(进程)中进行PV操作.
使用:
     1.CreateSemaphore 或OpenSemaphore
     2.ReleaseSemaphore(+n)
     3.WaitForSingleObject(-1)
     4.CloseHandle

遗弃问题:
     由于临界区是线程级别使用的,线程的操作都是由主线程控制的,当一个正在使用临界区的线程突然崩溃会怎么样呢?由于临界区会记录使用的线程,所以同样可以处理遗弃问题.

遗弃问题:
     由于进程(线程)突然死亡,而没有进行任何善后处理,这样会造成资源永远被占用,需要一种方法来解决.
 
解决之道
     当mutex使用者突然死了,那么mutex归零,等待其他使用者占有然后使用.
为什么event和semaphore不可以:
     因为event和semaphore并不记录其使用者,他的使用者死了event和semaphore并不知道,他只知道自己被使用,等待被释放.
     如果event和semaphore的使用者突然死亡,而其进程都在等待event和semaphore可用,那么这就造成了死锁.


为什么mutex和临界区(critical_section)不能进行同步:
   因为mutex和critical不能再主线程中使用,而信号量和事件都可以在主线程中使用.
   回忆一下,我们每次进行线程间同步的时候,总是先在主线程先设置事件或者信号量的状态,然后再在线程中设置,这样线程就可以使得线程有先后顺序了,即实现同步.核心在于主线程总是第一个执行,然后再执行子线程,这样就可以有先后顺序,如果不在主线程中设置,只是让子线程进行同步,也可以这需要一个全局变量,来进行检测是不是该这个线程执行.

我们用临界区+全局变量来实现一个线程同步:
#include <iostream>
#include <windows.h>
#include <process.h>
int g_count = 0;
CRITICAL_SECTION all;
unsigned int __stdcall producer (void *)
{
int ID = 0;
bool flage = true ;
while ( flage   ){
EnterCriticalSection (&all );
if ( g_count == ID ){
std ::cout << "producer"<< std ::endl ;
flage = false ;
g_count ++;
}
LeaveCriticalSection (&all );
}
return 0;
}
unsigned int __stdcall consumer (void *)
{
int ID = 1;
bool flage = true ;
while ( flage   ){
EnterCriticalSection (&all );
if ( g_count == ID ){
std ::cout << "consumer"<< std ::endl ;
flage = false ;
}
LeaveCriticalSection (&all );
}
return 0;
}
int main ()
{
InitializeCriticalSection(& all );
HANDLE hproducer = (HANDLE ) _beginthreadex( NULL ,0,producer , NULL,0, NULL );
HANDLE hconsumer = (HANDLE ) _beginthreadex( NULL ,0,consumer , NULL,0, NULL );
WaitForSingleObject( hproducer ,INFINITE );
WaitForSingleObject( hconsumer ,INFINITE );
return 0;
}

扩展:
      可不可以让信号量和事件实现遗弃呢? 
      当然可以,我们可以在线程调用信号量或事件的时候,在内核对象中添加该进程号.在进程表或其他地方注册一个回调函数,此函数功能是当该进程或线程崩溃的时候,通知相关内核对象(信号量内核对象或者事件内核内核对象),此线程已崩溃,删除该线程相关信息.
     此机制类似于epoll机制,有兴趣可以了解一下.


这篇关于多线程第七篇:互斥和同步总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1102972

相关文章

详谈redis跟数据库的数据同步问题

《详谈redis跟数据库的数据同步问题》文章讨论了在Redis和数据库数据一致性问题上的解决方案,主要比较了先更新Redis缓存再更新数据库和先更新数据库再更新Redis缓存两种方案,文章指出,删除R... 目录一、Redis 数据库数据一致性的解决方案1.1、更新Redis缓存、删除Redis缓存的区别二

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Java向kettle8.0传递参数的方式总结

《Java向kettle8.0传递参数的方式总结》介绍了如何在Kettle中传递参数到转换和作业中,包括设置全局properties、使用TransMeta和JobMeta的parameterValu... 目录1.传递参数到转换中2.传递参数到作业中总结1.传递参数到转换中1.1. 通过设置Trans的

C# Task Cancellation使用总结

《C#TaskCancellation使用总结》本文主要介绍了在使用CancellationTokenSource取消任务时的行为,以及如何使用Task的ContinueWith方法来处理任务的延... 目录C# Task Cancellation总结1、调用cancellationTokenSource.

Nacos集群数据同步方式

《Nacos集群数据同步方式》文章主要介绍了Nacos集群中服务注册信息的同步机制,涉及到负责节点和非负责节点之间的数据同步过程,以及DistroProtocol协议在同步中的应用... 目录引言负责节点(发起同步)DistroProtocolDistroSyncChangeTask获取同步数据getDis

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的