多线程编程中非常有用的提示和技巧
来源:互联网 发布:mac 读取exe 编辑:程序博客网 时间:2024/04/30 14:08
本文摘抄自《windows核心编程》
非常有用的提示和技巧
当使用关键代码段时,有些很好的方法可以使用,而有些方法则应该避免。下面是在使用
关键代码段时对你有所帮助的一些提示和技巧。这些技巧也适用于内核对象的同步(下一章介
绍)。
1. 每个共享资源使用一个C R I T I C A L S E C T I O N变量
如果应用程序中拥有若干个互不相干的数据结构,应该为每个数据结构创建一个
C R I T I C A L S E C T I O N变量。这比只有单个C R I T I C A L S E C T I O N结构来保护对所有共享资源的
访问要好,请观察下面这个代码段:
int g_nNums[100]; // A shared resource
TCHAR g_cChars[100]; // Another shared resource
CRITICAL_SECTION g_cs; //Guard both resources
DWORD WINAPI ThreadFunc(PVOID pvParam)
{
EnterCriticalSection(&g_cs);
for (int x=0; x<100; x++){
g_nNums[x] = 0;
g_cChars[x] = TEXT('X');
}
LeaveCriticalSection(&g_cs);
return 0;
}
这个代码使用单个关键代码段,以便在g n N u m s数组和g c C h a r s数组初始化时对它们同时
实施保护。但是,这两个数组之间毫无关系。当这个循环运行时,没有一个线程能够访问任何
一个数组。如果T h r e a d F u n c函数按下面的形式来实现,那么两个数组将分别被初始化:
DWORD WINAPI ThreadFunc(PVOID pvParam)
{
EnterCriticalSection(&g_cs);
for (int x=0; x<100; x++)
g_nNums[x] = 0;
for (x=0; x<100; x++)
g_cChars[x] = TEXT('X');
LeaveCriticalSection(&g_cs);
return 0;
}
从理论上讲,当g n N u m s数组初始化后,另一个只需要访问g n N u m s数组而不需要访问
g c C h a r s数组的线程就可以开始执行,同时T h r e a d F u n c可以继续对g c C h a r s数组进行初始化。
但是实际上这是不可能的,因为有一个关键代码段保护着这两个数据结构。为了解决这个问题,
可以创建下面两个关键代码段:
int g_nNums[100]; // A shared resource
CRITICAL_SECTION g_csNums; //Guard g_csNums
TCHAR g_cChars[100]; // Another shared resource
CRITICAL_SECTION g_csChars; //Guard g_csChars
DWORD WINAPI ThreadFunc(PVOID pvParam)
{
EnterCriticalSection(&g_csNums);
for (int x=0; x<100; x++)
g_nNums[x] = 0;
LeaveCriticalSection(& g_csNums);
EnterCriticalSection(&g_csChars);
for (int x=0; x<100; x++)
g_nNums[x] = 0;
LeaveCriticalSection(& g_csChars);
return 0;
}
运用这个实现代码,一旦T h r e a d F u n c完成对g n N u m s数组的初始化,另一个线程就可以开
始使用g n N u m s数组。也可以考虑让一个线程对g n N u m s数组进行初始化,而另一个线程函数
对g n C h a r s数组进行初始化。
2. 同时访问多个资源
有时需要同时访问两个资源。如果这是T h r e a d F u n c的要求,可以用下面的代码来实现:
DWORD WINAPI ThreadFunc(PVOID pvParam)
{
EnterCriticalSection(&g_csNums);
EnterCriticalSection(&g_csChars);
for (int x=0; x<100; x++)
g_nNums[x] = g_cChars[x];
LeaveCriticalSection(&g_csChars);
LeaveCriticalSection(&g_csNums);
return 0;
}
假定下面这个函数的进程中的另一个线程也要求访问这两个数组:
DWORD WINAPI ThreadFunc(PVOID pvParam)
{
EnterCriticalSection(&g_csChars);
EnterCriticalSection(&g_csNums);
for (int x=0; x<100; x++)
g_nNums[x] = g_cChars[x];
LeaveCriticalSection(&g_csNums);
LeaveCriticalSection(&g_csChars);
return 0;
}
在上面这个函数中我只是切换了对E n t e r C r i t i c a l S e c t i o n和L e a v e C r i t i c a l S e c t i o n函数的调用顺
序。但是,由于这两个函数是按上面这种方式编写的,因此可能产生一个死锁状态。假定
T h r e a d F u n c开始执行,并且获得了g c s N u m s关键代码段的所有权,那么执行O t h e r T h r e a d F u n c
函数的线程就被赋予一定的C P U时间,并可获得g c s C h a r s关键代码段的所有权。这时就出现
了一个死锁状态。当T h r e a d F u n c或O t h e r T h r e a d F u n c中的任何一个函数试图继续执行时,这两个
函数都无法取得对它需要的另一个关键代码段的所有权。
为了解决这个问题,必须始终按照完全相同的顺序请求对资源的访问。注意,当调用
L e a v e C r i t i c a l S e c t i o n函数时,按照什么顺序访问资源是没有关系的,因为该函数决不会使线程
进入等待状态。
3. 不要长时间运行关键代码段
当一个关键代码段长时间运行时,其他线程就会进入等待状态,这会降低应用程序的运行
性能。下面这个方法可以用来最大限度地减少关键代码段运行所花费的时间。这个代码能够防
止其他线程在W M S O M E M S G消息发送到一个窗口之前改变g s的值:
SOMESTRUCT g_s;
CRITICAL_SECTION g_cs;
DWORD WINAPI SomeThread(PVOID pvParam)
{
EnterCriticalSection(&g_cs);
//
SendMessage(hwndSomeWnd, WM_SOMEMSG, &g_s, 0 );
LeaveCriticalSection(&g_cs);
return 0;
}
无法确定窗口过程处理W M _ S O M E M S G消息时需要花费多长时间,它可能是几个毫秒,
也可能需要几年时间。在这个时间内,其他线程都不能访问g s结构。这个代码最好编写成下
面的形式:
SOMESTRUCT g_s;
CRITICAL_SECTION g_cs;
DWORD WINAPI SomeThread(PVOID pvParam)
{
EnterCriticalSection(&g_cs);
SOMESTRUCT sTemp = g_s;
LeaveCriticalSection(&g_cs);
//
SendMessage(hwndSomeWnd, WM_SOMEMSG, &sTemp, 0 );
return 0;
}
这个代码将该值保存在临时变量s Te m p中。也许你能够猜到C P U需要多长时间来执行这行
代码—只需要几个C P U周期。当该临时变量保存后,L e a v e C r i t i c a l S e c t i o n函数就立即被调用,
因为这个全局结构不再需要保护。上面的第二个实现代码比第一个要好得多,因为其他线程只
是在几个C P U周期内被停止使用g s结构,而不是无限制地停止使用该结构。当然,这个方法
的前提是该结构的“瞬态图”应当做到非常好才行,以方便于窗口过程读取。此外,窗口过程
不需要改变该结构中的成员。
- 多线程编程中非常有用的提示和技巧
- ASP 编程中非常有用的例子
- 在VB中非常有用的数组
- java中非常有用的接口jni
- flex中非常有用的两个包
- Eclipse中非常有用的快捷键组合
- oracle中非常有用的查询语句
- PHP中非常有用的函数
- DirectX SDK 中非常有用的一段代码
- Editplus中非常有用的正则替换式
- 4个DEDE开发中非常有用的功能
- SQL%NOTFOUND在实际中非常有用
- Matlab中非常实用的快捷键和命令
- HTML中非常有用的但容易被忽略的属性
- Eclipse 中非常有用的5个功能,纠结ing,居然没发现。
- 21个非常有用的 .htaccess 提示和技巧
- Web 开发中 9 个有用的提示和技巧
- 21 个非常有用的 .htaccess 提示和技巧
- python中的编码模式
- 文件流总结
- 淡薄人生,宁静致远
- static变量与asp.net
- 向往梦想的小熊
- 多线程编程中非常有用的提示和技巧
- 如何成为顶级的程序员
- 在aspx里嵌入播放器.这个是播放flash视频的
- 文本与二进制内容的存取操作
- JS复制文本框内容
- 关于跳过flex的sandbox实现访问本地资源的解决方案
- 小曹谈技术之索引&词典结构
- ibatis对存储过程的调用
- C# 加密方式汇总(摘自http://www.cnblogs.com/heimirror/archive/2008/10/13/1309728.html)