《Windows核心编程》读书心得——线程(线程同步)(4)

l 用户模式下的线程同步:

                                               

Volatile类型:告诉编译器必须到内存取变量值,而不使用寄存器中的值。因为每个线程都有各自的寄存器,它们的寄存器中同一变量的值可能不一致。(例如嵌入汇编代码,编译器无法觉察到变量已经被修改了)

 

原子访问:指的是一个线程在访问某个资源的时候,能够保证没有其他线程访问该资源。

相关函数:

InterlockedExchangeAdd):原子加减法(传负值表示做减法);

InterlockedIncrement):原子加法;

InterlockedExchange):原子替换;

InterlockedCompareExchange)。

原理:Interlocked函数会在总线上维持一个硬件信号,该信号阻止其他CPU访问同一个内存地址

原子锁的速度很快

一般在多CPU的机器上比较有用,在单CPU机器上不使用原子锁。

 

关键段:

(1)      定义一个CRITICAL_SECTION结构的变量g_cs

(2)      调用InitialsizeCriticalSection&g_cs)初始化;

(3)      把需要共享的代码放在EnterCriticalSection( &g_cs )LeaveCriticalSection( &g_cs )之间(还有TryEnterCriticalSection函数);

(4)      调用DeleteCriticalSection&g_cs)释放;

(当已有一个线程访问被锁定的资源,另一个线程想要访问,必须进入等待状态)

(5)      旋转锁:可以在使用关键段的同时使用旋转锁,以提高效率。(相关函数:InitalizeCriticalSectionAndSpinCount()、SetCriticalSectionSpinCount())。

 

      (为什么加旋转锁能够提高效率?

        因为当一个线程试图进入一个关键段,而该关键段正被另一个线程占用,此时该线程会切换到等待状态。也就是说需要从用户模式切换到内核模式,这样会影响关键段的效率。加了旋转锁,线程就会再一段时间不断尝试进入关键段,只有多次尝试失败,才会进入等待状态,这样就减少了经常切换到内核模式,从而提高效率。)

 

Slim/写锁:

(1)      初始化:InitializeSRWLock();

(2)      读锁:AcquireSRWLockExclusive()、ReleaseSRWLockExclusive();

(3)      写锁:AcquireSRWLockShared()、ReleaseSRWLockShared()。

 

      (读锁和写锁的区别:读锁允许多个线程同时读取一块数据,因为仅仅读取数据并不会更改数据,因此不需要考虑同步的问题;写锁要求独占对资源的访问权,因此,在一个线程写入数据时,其他线程不允许对数据进行读或写。)

 

效率先后:volatile、原子访问、读写锁、关键段、内核对象。

 

volatile:非常快;

原子访问:CPU需要锁定内存,因此比volatile慢;

关键段:比较慢,因为包含进入和离开两个操作,并且这两个操作需要修改CRITICAL_SECTION结构中多个字段;

读写锁:读比写快,因为读数据可以多个线程同时进行,写数据必须独占进行;

内核对象(如:互斥量):比较慢,总是需要在用户模式和内核模式之间切换。

 

l 用内核对象进行线程同步:

 

内核对象的状态:对线程同步来说,每一种内核对象要么处于触发状态,要么处于非触发状态(例如,进程内核对象在创建的时候处于非触发状态,在终止的时候变成触发状态)。

 

等待函数:

WaitForSingleObject():等待单个对象触发;

WaitFoMultipleObjects():等待多个对象触发;

 

事件内核对象实现线程同步:

1)创建事件内核对象:

可通过CreateEvent()或CreateEventEx()函数创建事件内核对象,被创建的事件可以是自动重置事件或手动重置事件。

2)事件内核对象同步:

在不同线程中,可通过DuplicateHandle()或OpenEvent()来访问已经创建的事件内核对象。

3)重置事件内核对象:

SetEvent():将事件变成触发状态;

ResetEvent():将事件变成非触发状态。

 

可等待的计时器内核对象:

它可以在某个指定的时间触发,或每隔一段时间触发一次。

1)相关函数:

CreateWaitableTimer():创建计时器;

OpenWaitableTimer():打开已经存在的计时器;

SetWaitableTimer():设置计时器;

CancleWaitableTimer():撤销计时器;

2)和用户计时器(OnTimer)比较:

1.用户计时器需要大量的用户界面基础设施,从而消耗更多资源;

2.可等待计时器是内核对象,可在多个线程之间共享,可具备安全性;而用户计时器触发时,只有一个线程得到通知

3. WM_TIMER消息的优先级是最低的,只有当线程消息队列中没有其他消息的时候才会被处理。

 

信号量内核对象:

信号量内核对象用来对资源进行计数,包含两个参数:一个最大资源计数和一个当前资源计数。

 

互斥量:

互斥量内核对象用来确保一个线程独占对一个资源的访问,它的优势在于能在不同的进程间共享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值