VC++多线程工作笔记0006---线程间同步机制2

it2023-02-12  53

技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152

还是用上次的工程

把代码copy到vs中

CreateMutex这个是个系统默认核心对象,这个第一个参数,LPSECURITY_ATTRIBUTES,肯定是需要的

这里我们用默认安全级别,填写NULL就可以.

这个bInitialOwner,一般是填写false,就是这个互斥锁是共享的,

填写true就是说这个互斥锁被当前这个线程所拥有,不过这里填写true,false一般没有什么区别.

第三个是,这互斥器的名字.通过这个名字,可以在一个进程中创建互斥器,在另一个进程中打开互斥器.

 

因为我们这里不涉及到多个进程间通信使用,所以这里第三个参数我们传递NULL

可以看到这个函数如果返回的是NULL,说明出现了错误,可以通过GetLastError这个函数,来获取错误信息

然后如果返回的是

返回的是这个ERROR_ALREADY_EXISTS的话,那么说明这个互斥器就已经存在了

这里在创建线程按钮中,启动50个线程.

然后

然后线程函数中去使用这个互斥器,使用的时候

要在给字符串数组添加元素的时候,首先使用互斥器,进行等待.

WaitForSingleObject(ghMutex,INFINITE)

这个函数

 

这个WaitForSingleObject这个互斥器,第一个参数是哪个互斥器的句柄

这里定义了一个互斥器句柄.

第二个参数是,多长时间超时.

比如来了一个线程,去执行,这个往字符串数组中添加元素,这个时候先执行

WaitForSingleObject这个函数,执行的时候,会获取到一个结果,就是说,

别的线程有没有正在添加元素,如果正在操作的话,这个就会返回一个waitfor,就是返回需要等待的一个标志

如果没有别的线程正在操作的话,就可以直接进入了给字符串数组添加元素了.

这INFINITE这个是默认的超时时间.1000,就是1s,毫秒为单位.

这个WAIT_OBJECT_0意思就是说,被保护的代码,目前没有被其他线程使用,现在

可以使用这部分代码

另外如果返回WAIT_ABANDONED这个是什么意思呢?

上节课说的用Critical Sections的时候,咱们说如果执行了EnterCritical,但是还没有来得及执行

LeaveCritical,接着这个线程就结束了,导致,被锁的部分代码,就被锁住了,别的线程就不能用了,没有解决办法.

 

这里用这互斥锁mutex就可以解决了,

这里有个WAIT_ABANDONED,就是说,如果某个线程,调用WaitForSingleObject等待的时候,还没有来得及

releaseMutex就结束了,这样这里获取的这个WaitResult就会是WAIT_ABANDONED,这样就能处理这种情况了.

 

然后用完以后要记得releaseMutex(ghMutex)然后ghMutex这个是互斥对象的句柄.

然后在我要看结果按钮中,最后用完要记得,关闭这个互斥对象

CloseHandle(ghMutex);

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

信号量来实现线程同步

上面几种不管是互斥锁,还是Critical Section,还是用原子锁,

都是一个线程,同时操作一个逻辑,这样来保护这个逻辑,不受多线程的影响,

这个信号量,允许,支持多个线程同一时间操作多个对象.

举个例子,

比如租车,我们有10台车,但是有50个人要租,那么应该是

有10个人可以同时租到车.也就是多个线程同一时间可以操作多个对象

 

另外前面咱们讲的互斥锁,还是Critical Section,还是用原子锁都是10台车,50个人要租,

但是能,同一时间,只能一个人去用一台车.

 

举个例子:

可以看到这里

CreateSemaphore这里有4个参数

第一个是LPSECURITY_ATTRIBUTES是安全属性,用不到可以填入NULL

第二个参数是lInitialCount

第三个参数是lMaximumCount

这两个的参数意思是,lMaximumCount这个相当于一共有多少资源,类似于上面的10台车,那么

lInitialCount是开始使用的时候,允许一次使用几台车,使用多少资源,一般

lInitialCount要小于等于lMaximumCount

然后

lpName这个是给这个信号量,起了个名字.

首先我们定义一个信号量

ghSemaphore

然后我们在创建线程按钮中创建信号量

CreateSemaphore(NULL,10,10,NULL)

这个第一个NULL 是线程安全属性传入NULL,

第二个是初始的可以使用的资源数量

第三个是总共有的资源数量

第4个是NULL是信号量的名字可以起一个,用不到可以传入NULL

 

然后它再创建50个线程,然后同时去操作,传入idx

然后再去看看这个线程函数,

这里就是不停的打印出,这个当前线程的id

 

然后打印完以后,用完了信号量,把信号量释放

ghSemaphore,注意这里

ReleaseSemaphore(ghSemaphore,1,NULL)

第一个参数是ghSemaphore这个是信号量,1这个是要释放多少个资源,这里是释放1个,然后最后一个,

以前的个数不用管,传入NULL

使用的时候开始要

调用

WairForSingleObject(ghSemaphore,0);来获取信号量

这里的0的作用,就是不等待,意思就是,比如原来有1个厕所,现在我们有10个厕所,那么就不用等待了,也没有

超时时间了.这里超时时间就设置为0.

并且获取信号量的结果

并且这里判断结果,是WAIT_OBJECT_0的时候

这里进行输出,然后ReleaseSemaphore(ghSemaphore,1,NULL);

如果是请求的时候,比如10个信号量用完了,那么就会产生等待,

WAIT_TIMEOUT的时候,就要进行等待的处理.

用完了以后,最后还要进行关闭句柄.

然后在这里

这里执行一下,点击创建线程,可以看到debugview中显示的可以看到也有wait timed out!的

这个Event的方式,如果是车的话,上面咱们说的,

互斥锁,信号量,共享变量,Critical Section可以认为是自动档的,因为每当

WaitForSingleObject被一个线程调用的时候,自动会变成无信号的,如果是信号量的话,

这个时候,别的线程调用的时候就没办法用了,而

这个Event事件是可以允许自己去设置的,

比如自己去设置当WaitForSingleObject被调用的时候,自己去设置这个信号,自己去setevent设置信号,以及释放信号.

看例子

这里如果是bManualReset这个变量如果是false的话就是自动设置,就是说,使用方法,跟上面说的信号量是一样的,

但是如果是true的话,那么就不是自动设置,也就说,需要自己去,调用WaitForSingleObject的时候,去把信号量

设置为无信号的,非激发状态.

然后用完以后再用SetEvent设置为激发状态,再释放信号.

lpName是事件的名称,第一个lpEentAttributes,是线程安全属性

这里第一个参数是NULL,第二个参数是TRUE表示,手动设置信号,

第三个参数是TRUE,表示手动设置的是激发态,也就是需要手动设置信号的释放.

这个事件的方式的多线程同步,没有举例子,具体的例子,到时候用的时候去查一下吧.通过事件进行线程间同步.

 

credreamer~夹狗狮 认证博客专家 推荐算法 算法 神经网络 从事10年编程工作,工作涉及到.Net,Java,C等编程语言,爱好领域,算法,人工智能,大数据等领域, 虚心求教,一起进步,credream 创梦 是大学期间想的个词,如今一晃10多年已过....
最新回复(0)