Win32下两种用于C++的线程同步类(上) |
|
www.nanhushi.com 佚名 不详 |
线程同步是多线程程序设计的核心内容,它的目的是正确处理多线程并发时的各种问题,例如线程的等待、多个线程访问同一数据时的互斥,防死锁等。Win32提供多种内核对象和手段用于线程同步,如互斥量、信号量、事件、临界区等。所不同的是,互斥量、信号量、事件都是Windows的内核对象,当程序对这些对象进行控制时会自动转换到核心态,而临界区本身不是内核对象,它是工作在用户态的。我们知道从用户态转换到核心态是需要以时间为代价的,所以如果能在用户态就简单解决的问题,就可以不必劳烦核心态了。
这里我要说的是两种用于C++的多线程同步类,通过对这两种类的使用就可以方便的实现对变量或代码段的加锁控制,从而防止多线程对变量不正确的操作。
所谓加锁,就是说当我们要访问某关键变量之前,都需要首先获得允许才能继续,如果未获得允许则只有等待。一个关键变量拥有一把锁,一个线程必须先得到这把锁(其实称为钥匙可能更形象)才可以访问这个变量,而当某个变量持有这把锁的时候,其他线程就不能重复的得到它,只有等持有锁的线程把锁归还以后其他线程才有可能得到它。之所以这样做,就是为了防止一个线程读取某对象途中另一线程对它进行了修改,或两线程同时对一变量进行修改,例如:
// 全局: struct MyStruct ... { int a, b; } ; MyStruct s; // 线程1: int a = s.a; int b = s.b; // 线程2: s.a ++ ; s.b -- ; 如果实际的执行顺序就是上述书写的顺序那到没有什么,但如果线程2的执行打断了线程1,变为如下顺序:
int a = s.a; //线程1 s.a++; //线程2 s.b++; //线程2 int b = s.b; //线程1 那么这时线程1读出来的a和b就会有问题了,因为a是在修改前读的,而b是在修改后读的,这样读出来的是不完整的数据,会对程序带来不可预料的后果。天知道两个程的调度顺序是什么样的。为了防止这种情况的出现,需要对变量s加锁,也就是当线程1得到锁以后就可以放心的访问s,这时如果线程2要修改s,只有等线程1访问完成以后将锁释放才可以,从而保证了上述两线程交叉访问变量的情况不会出现。
使用Win32提供的临界区可以方便的实现这种锁:
// 全局: CRITICAL_SECTION cs; InitializeCriticalSection( & cs); // 线程1: EnterCriticalSection( & cs); int a = s.a; int b = s.b; LeaveCriticalSection( & cs); // 线程2: EnterCriticalSection( & cs); s.a ++ ; s.b -- ; LeaveCriticalSection( & cs); // 最后: DeleteCriticalSection( & cs); 代码中的临界区变量(cs)就可以看作是变量s的锁,当函数EnterCriticalSection返回时,当前线程就获得了这把锁,之后就是对变量的访问了。访问完成后,调用LeaveCriticalSection表示释放这把锁,允许其他线程继续使用它。
|
|
|
文章录入:杜斌 责任编辑:杜斌 |
|
上一篇文章: Win32下两种用于C++的线程同步类(下) 下一篇文章: MoreEffectiveC++之效率 |
【字体:小 大】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口】 |
|
|