实现进程互斥的核心思想比较简单:进程在启动时首先检查当前系统是否已经存在有此进程的实例,如果没有,进程将成功创建并设置标识实
例已经存在的标记。此后再创建进程时将会通过该标记而知晓其实例已经存在,从而保证进程在系统中只能存在一个实例。具体可以采取内存
映射文件、有名事件量、有名互斥量以及全局共享变量等多种方法来实现。下面就分别对其中具有代表性的有名互斥量和全局共享变量这两种
方法进行介绍:
// 创建互斥量
HANDLE m_hMutex = CreateMutex(NULL, FALSE, "Sample07");
// 检查错误代码
if (GetLastError() == ERROR_ALREADY_EXISTS) {
// 如果已有互斥量存在则释放句柄并复位互斥量
CloseHandle(m_hMutex);
m_hMutex = NULL;
// 程序退出
return FALSE;
}
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // 指向安全属性的指针
BOOL bInitialOwner, // 初始化互斥对象的所有者
LPCTSTR lpName // 指向互斥对象名的指针
);
使用全局共享变量的方法则主要是在MFC框架程序中通过编译器来实现的。通过#pragma data_seg预编译指令创建一个新节,在此节中可用
volatile关键字定义一个变量,而且必须对其进行初始化。Volatile关键字指定了变量可以为外部进程访问。最后,为了使该变量能够在进程
互斥过程中发挥作用,还要将其设置为共享变量,同时允许具有读、写访问权限。这可以通过#pragma comment预编译指令来通知编译器。下面
给出使用了全局变量的进程互斥代码清单:
#pragma data_seg("Shared")
int volatile g_lAppInstance =0;
#pragma data_seg()
#pragma comment(linker,"/section:Shared,RWS")
……
if(++g_lAppInstance>1)
return FALSE;
此段代码的作用是在进程启动时对全局共享变量g_nAppInstancd 加1 ,如果发现其值大于1,那么就返回FALSE以通知进程结束。这里需要
特别指出的是,为了使以上两段代码能够真正起到对进程互斥的作用,必须将其放置在应用程序的入口代码处,即应用程序类的初始化实例函
数InitInstance()的开始处。
VOID ExitProcess(UINT uExitCode);
ExitProcess()只能强制执行本进程的退出,如果要在一个进程中强制结束其他的进程就要用TerminateProcess()来实现。与ExitProcess
()不同,TerminateProcess()函数执行后,被终止的进程是不会得到任何关于程序退出的通知的。也就是说,被终止的进程是无法在结束
运行前进行退出前的收尾工作的。所以,通常只有在其他任何方法都无法迫使进程退出时才会考虑使用TerminateProcess()去强制结束进程
的。下面给出TerminateProcess()的函数原型:
BOOL TerminateProcess(HANDLE hProcess, UINT uExitCode);
参数hProcess和uExitCode分别为进程句柄和退出代码。如果被结束的是本进程,可以通过GetCurrentProcess()获取到句柄。
TerminateProcess()是异步执行的,在调用返回后并不能确定被终止进程是否已经真的退出,如果调用TerminateProcess()的进程对此细
节关心,可以通过WaitForSingleObject()来等待进程的真正结束。
使用临界区保持线程同步:
北京 上海 广东
重庆 成都 沈阳用户
登录
Chinabyte.com|Techtarget.com.cn
Excel服务器学习下载
免费去香港看迪斯尼!
JAVA工程师定向委培
超爽游戏 想玩就点我
软件高手训练营手机交流互动
TM2005办公沟通更轻松
微软最新系统Vista专区
百度中秋,有奖游戏
工具软件 办公软件 操作系统 网络安全 设计在线 程序开发 教程宝典 软件下载 软件论坛
您的位置: 软件 > 开发者网络 > 开发工具 > 开发专栏 > VC > 正文
Visual C++线程同步技术剖析
Google提供的广告
电子工程专辑: cpld 编程
PLD/fpga等可编程逻辑器件的新闻趋势
新品动态,设计技术和应用实例每日更新
www.eetchina.com
北大青鸟aptech(珠海前程)
IT培训、软件测试工程师、软件工程师
网络工程师培训.免费电话:8008303575
www.zh-aptech.com.cn
Java/C++/游戏高薪就业培训
中兴/华为/中软/志鸿等知名企业直通车
IT就业培训黄金品牌,月薪4K保证就业.
www.5itjob.com
[文章信息]
作者: 中国电波传播研究所 郎锐
时间: 2004-02-24
出处: yesky
责任编辑: 方舟
[文章导读]
本文重点对多线程的各种同步技术进行介绍
·国内最大中文桌面壁纸站:天极桌面
·软件专题教程宝典 软件的知识宝库
·国内最大游戏 动漫 COSPLAY图片站
·天极博客 动手构建自己的网上家园
·天极网摘 看大家为你精选出来的东西
·天极资料世界 您想找的我们都已备好
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
advertisement
软件频道精华文章
新版软件频道
QQ2006贺岁版新功能挨个看
QQ2006贺岁版漂亮QQ主题包随心换
让你轻松下载网络流行歌曲
看上去很美 黄色网站背后隐藏的安全危机
微软全新Win Vista CTP版新功能抢先预览
系统维护宝典 Windows系统故障修复技巧
数码婚纱照片Photoshop抠图技巧
轻轻松松看视频 快快乐乐学设计
树木枝叶的四种Photoshop抠图方法
五彩缤纷:45款超炫XP登陆界面随意换
用美女大头像制作超级海报
人像照片后期处理技巧:皮肤修饰
千万别算!装机最贵与免费的十大软件
决不夸张 让Windows XP系统快10倍
微软新一代办公软件:Office 2007
教你如何将下载的电影刻录成VCD
特别视线:色情网站背后隐藏的秘密
虚拟计算机 Virtual PC安装使用指南
用Excel建立一套小型人事数据管理系统
视频格式转换工具使用集锦
照片处理:Photoshop打造惊艳国画美女
全面进入新世界 走向64位Windows系统
绝密:远程破解盗窃QQ密码的内幕(图)
照片处理:美女肖像照片靓肤技巧
PS自定义形状工具巧做可爱造型宝宝照片
解密Windows Vista 5270中的捆绑程序
真正的Windows XP操作系统启动加速
PDF转Word怎么转 多种方法可实现
为照片MM打造幼嫩光滑又不失真的好皮肤
腾讯QQ2005珊瑚虫版v4.1a发布
关注PC健康 电脑使用变慢七大原因
QQ2006贺岁版 新春新体验
经验共享 19招让Win XP系统运行得更快
创意做月历 快乐过新年
Photoshop将照片变为十字绣效果
Photoshop蒙版妙用:无痕合成美女照片
教你玩QQ2006Beta1新功能3D秀
攻防演练 魔兽世界帐号的窃取与防范
笔记本电脑操作系统优化八大技巧
提示QQ号码需要激活无法登录的解决办法
菜鸟必看:学习黑客技术的基本环境
黎明中的64位 Win XP64位与32位性能对比
网友体验 如何让系统启动时间减少一半
QQ2006Beta1发布 3D秀+新聊天窗口赚眼球
妙用好工具 菜鸟也能改造Win XP安装盘
改个文件 让珊瑚虫QQ显出隐身好友
我该如何面对你 烦人的流氓软件
一“键”行天下 Windows一键操作技巧
Photoshop鼠绘实例:逼真苹果
想慢都不行 Win XP快速启动最新技巧
Google提供的广告
电子工程专辑: cpld 编程
PLD/fpga等可编程逻辑器件的新闻趋势新品动态,设计技术和应用实例每日更新
www.eetchina.com
Java/C++/游戏高薪就业培训
中兴/华为/中软/志鸿等知名企业直通车IT就业培训黄金品牌,月薪4K保证就业.
www.5itjob.com
深圳优迈:IT就业培训
深圳软件行业协会就业培训中心深圳0755-88833220武汉027-87877627
www.umltech.cn
热点推荐
· 深入探讨SQL Server 2000对XML的支持
· Swing(空)
· 3DS Stodio Max 宝典
· 中小企业服务器配置方案--前 言
· 中小企业服务器配置方案--代理接入服务器(3)
[正文] 注册域名,免费游香港迪斯尼 买笔记本,打800-858-0410国内最低价,还有优惠 上一页 1 2 3 4 5 下一页
临界区
临界区(Critical Section)是一段独占对某些共享资源访问的代码,在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程
试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在
被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。
临界区在使用时以CRITICAL_SECTION结构对象保护共享资源,并分别用EnterCriticalSection()和LeaveCriticalSection()函数去标
识和释放一个临界区。所用到的CRITICAL_SECTION结构对象必须经过InitializeCriticalSection()的初始化后才能使用,而且必须确保所有
线程中的任何试图访问此共享资源的代码都处在此临界区的保护之下。否则临界区将不会起到应有的作用,共享资源依然有被破坏的可能。
图1 使用临界区保持线程同步
下面通过一段代码展示了临界区在保护多线程访问的共享资源中的作用。通过两个线程来分别对全局变量g_cArray[10]进行写入操作,用
临界区结构对象g_cs来保持线程的同步,并在开启线程前对其进行初始化。为了使实验效果更加明显,体现出临界区的作用,在线程函数对共
享资源g_cArray[10]的写入时,以Sleep()函数延迟1毫秒,使其他线程同其抢占CPU的可能性增大。如果不使用临界区对其进行保护,则共享
资源数据将被破坏(参见图1(a)所示计算结果),而使用临界区对线程保持同步后则可以得到正确的结果(参见图1(b)所示计算结果)。
代码实现清单附下:
// 临界区结构对象
CRITICAL_SECTION g_cs;
// 共享资源
char g_cArray[10];
UINT ThreadProc10(LPVOID pParam)
{
// 进入临界区
EnterCriticalSection(&g_cs);
// 对共享资源进行写入操作
for (int i = 0; i < 10; i++)
{
g_cArray[i] = 'a';
Sleep(1);
}
// 离开临界区
LeaveCriticalSection(&g_cs);
return 0;
}
UINT ThreadProc11(LPVOID pParam)
{
// 进入临界区
EnterCriticalSection(&g_cs);
// 对共享资源进行写入操作
for (int i = 0; i < 10; i++)
{
g_cArray[10 - i - 1] = 'b';
Sleep(1);
}
// 离开临界区
LeaveCriticalSection(&g_cs);
return 0;
}
……
void CSample08View::OnCriticalSection()
{
// 初始化临界区
InitializeCriticalSection(&g_cs);
// 启动线程
AfxBeginThread(ThreadProc10, NULL);
AfxBeginThread(ThreadProc11, NULL);
// 等待计算完毕
Sleep(300);
// 报告计算结果
CString sResult = CString(g_cArray);
AfxMessageBox(sResult);
}
在使用临界区时,一般不允许其运行时间过长,只要进入临界区的线程还没有离开,其他所有试图进入此临界区的线程都会被挂起而进入
到等待状态,并会在一定程度上影响。程序的运行性能。尤其需要注意的是不要将等待用户输入或是其他一些外界干预的操作包含到临界区。
如果进入了临界区却一直没有释放,同样也会引起其他线程的长时间等待。换句话说,在执行了EnterCriticalSection()语句进入临界区后
无论发生什么,必须确保与之匹配的LeaveCriticalSection()都能够被执行到。可以通过添加结构化异常处理代码来确保
LeaveCriticalSection()语句的执行。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。
MFC为临界区提供有一个CCriticalSection类,使用该类进行线程同步处理是非常简单的,只需在线程函数中用CCriticalSection类成员函
数Lock()和UnLock()标定出被保护代码片段即可。对于上述代码,可通过CCriticalSection类将其改写如下:
// MFC临界区类对象
CCriticalSection g_clsCriticalSection;
// 共享资源
char g_cArray[10];
UINT ThreadProc20(LPVOID pParam)
{
// 进入临界区
g_clsCriticalSection.Lock();
// 对共享资源进行写入操作
for (int i = 0; i < 10; i++)
{
g_cArray[i] = 'a';
Sleep(1);
}
// 离开临界区
g_clsCriticalSection.Unlock();
return 0;
}
UINT ThreadProc21(LPVOID pParam)
{
// 进入临界区
g_clsCriticalSection.Lock();
// 对共享资源进行写入操作
for (int i = 0; i < 10; i++)
{
g_cArray[10 - i - 1] = 'b';
Sleep(1);
}
// 离开临界区
g_clsCriticalSection.Unlock();
return 0;
}
……
void CSample08View::OnCriticalSectionMfc()
{
// 启动线程
AfxBeginThread(ThreadProc20, NULL);
AfxBeginThread(ThreadProc21, NULL);
// 等待计算完毕
Sleep(300);
// 报告计算结果
CString sResult = CString(g_cArray);
AfxMessageBox(sResult);
}