CMutex使用时的注意事项,以及CMutex::Unlock何时会返回0

摘要:同一个CMutex对象不允许在两个线程中分别调用Lock和Unlock,否则Unlock会失败并返回0。

一、问题描述

笔者最近在开发过程中遇到了CMutex::Unlock返回0的情况,通过MSDN得知这表示Unlock失败。但MSDN并没有告诉我为什么会失败以及如何处理,查百度谷歌亦无果,于是决定动手探索。

这是MSDN上Unlock对返回值的解释

Return Value

Default implementation always returns TRUE.

Remarks

The default implementation of the declaration with two parameters always returns
TRUE. This function is called to release access to the synchronization object owned by the calling thread. The second declaration is provided for synchronization objects such as semaphores that allow more than one access of a controlled resource.

二、产生问题的原因

产生问题的原因如摘要所述:同一个CMutex对象不允许在两个线程中分别调用Lock和Unlock,否则Unlock会失败并返回0。(P.S.这可能并不是唯一会使Unlock返回0的原因,笔者这次是这个原因)

三、例程

1、源码

#include "stdafx.h"
#include "stdlib.h"
#include "afxmt.h"
#include <iostream>
using namespace std;

CMutex g_objLock;

DWORD WINAPI ThrdFun1(LPVOID lpParam)//
{
	int iResult,iResult1,i=0,iTest;
	int iCount=0,iCycle=1;

	for(i=0;i<9999;i++)
	{
		g_objLock.Lock();
		printf("ThrdFun1:%d\n",i);
		g_objLock.Unlock();
		Sleep(1000);
	}

	return 0;
}

DWORD WINAPI ThrdFun2(LPVOID lpParam)//
{
	int iResult,iResult1,i=0,iTest;
	int iCount=0,iCycle=1;
	int iSleep=5;

	/*printf("ThrdFun2:lock and sleep %d sec\n",iSleep);
	g_objLock.Lock();
	Sleep(iSleep*1000);*/
	iResult=g_objLock.Unlock();
	printf("ThrdFun2:unlock ret %d\n",iResult);

	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	int iResult,iResult1,i=0,iTest;
	int iSleep=5;

	printf("start 1\n");
	CreateThread(NULL, 0, ThrdFun1, NULL, 0, NULL);
	printf("sleep %d sec\n",iSleep);
	Sleep(iSleep*1000);

	printf("lock and sleep %d sec\n",iSleep);
	g_objLock.Lock();
	Sleep(iSleep*1000);
	iResult=g_objLock.Unlock();
	printf("unlock ret %d\n",iResult);

	printf("sleep %d sec\n",iSleep);
	Sleep(iSleep*1000);

	printf("lock and sleep %d sec\n",iSleep);
	g_objLock.Lock();
	Sleep(iSleep*1000);
	printf("start 2\n");
	CreateThread(NULL, 0, ThrdFun2, NULL, 0, NULL);  

	Sleep(999*1000);

	system("pause");
	return 0;
}

环境是vs2005,建工程的时候选择了预编译头,所以会有stdafx.h。

2、运行结果

可以看到第一次Unlock在主线程中,成功并返回1;第二次Unlock在线程2中,失败并返回0,之后g_objLock一直处于锁定状态,线程1永久阻塞。

四、在MFC中使用CMutex

MFC的消息处理是单线程的,所以可以在2个消息处理函数中分别调用Lock和Unlock。使用CreateThread等API创建线程时,任何在线程的入口函数中Lock的CMutex对象都不能在消息处理函数Unlock,反之亦然。

另外经测试在同一个线程中连续两次调用Lock并不会使线程阻塞(第二次Lock直接返回),所以在2个消息处理函数中分别调用一次Lock不会使它们互相锁定。

时间: 2024-10-24 08:07:02

CMutex使用时的注意事项,以及CMutex::Unlock何时会返回0的相关文章

time.h文件中包含的几个函数使用时须注意事项

time.h头文件中包含以下函数 char* asctime(const struct tm *tm); char* asctime_r(const struct tm *tm,char *buf); char* ctime(const time_t *timep); char* ctime_r(const time_t *timep,char *buf); struct tm *gmtime(const time_t *timep); struct tm *gmtime_r(const tim

#if #elif #define typedef 使用时的注意事项

假设有如下代码需要兼容三个版本 这样无法完成任务的 无论 typedef enum{ FIRST, SECOND, THIRD, }; #define NUM THIRD #if (NUM == FIRST) #define VAR 1 #elif(NUM == SECOND) #define VAR 2 #elif(NUM == THIRD) #define VAR 3 #endif int main(void) { #if (NUM == FIRST) printf("VAL = %d\n&

opencv Mat 使用时的注意事项

下面的small tips 是我在做毕设时处理图片遇到的一些问题,先如今都已经找到了解决的方法,适合于opencv的新手看一看. 1. imread() 小陷阱 imread('img.jpg'); 这条语句读进来的是3通道,无论img.jpg是单通道的图像还是3通道的图像,所以输入图像如果是灰度图像,为了不出错,可以使用 imread("img.jpg",-1); 2.normalize() 小陷阱 要注意它的输入矩阵必须是单通道的,具体可见下方红色部分. <span styl

UITableViewCell使用时注意事项

1,注意使用重用机制(有利于提高效率) 2,做到通过改变模型去间接改变UI样式(做到永久改变,无论怎样拖动刷新,都不会恢复改变) 3,在通过传递模型给Cell控件布局时,记得完全覆盖(嗯,不好解释,主要是在重用机制引起的,如果不完全覆盖,则在重用时,可能被另外一个cell引用,造成显示数据的错误) 4,自定义cell时,添加控件尽量添加到cell的contentView内部,因为cell自动封装了滑动删除等功能,而该功能的实现中有通过缩放contentView来显示"删除"按钮的,所以

EntityFrameWork 使用时碰到的小问题

EntityFrameWork 使用时碰到的小问题 1,在使用orm访问数据库的相目里,也要引用EntityFrameWork.dll,否则无法使用orm 否则,编译错误 错误 5 "System.Data.Entity.DbSet`1<DbAccess.Entity.Dept>"不包含"Where"的定义,并且找不到可接受类型为"System.Data.Entity.DbSet`1<DbAccess.Entity.Dept>&qu

Highcharts使用时遇到的问题及解决方案

Highcharts使用时遇到的问题及解决方案 Highcharts图表控件功能强大,对细节处理得很细致,是目前使用最为广泛的图表控件.本文总结了作者在使用Highcharts时遇到的问题及解决方案. 1. 图表颜色设置 图表的边框色,背景色及点.线的颜色都是可以设置的,其中边框色(borderColor).背景色(backgroundColor)在chart中设置: chart: { backgroundColor: 'pink',// 背景色 borderColor: 'red',// 边框

bootstrap使用时 细节心得

最近国庆7天 还原某丽说 APP PC端网页(作业)时  全程使用bootstrap制作 也遇到了以前很少碰到过的问题 bootstrap 本身修改了某些默认样式  即使在 未给标签class命名某个bootstrap模板时  某些标签也被修改过  这样会容易使某些像我一样的新手误以为自己写的代码哪里出了问题  而浪费很多时间去找一个 没有错误的错误  所以在这里给各位同学做个温馨提示 例如 fieldset 中 lengd标签中的文字 应该是水平居中 位于两侧横线中间 并且垂直居中于横线 但在

c语言:宏里面参数不加括号容易出错,在使用时尽量加括号及举例

宏里面参数不加括号容易出错,在使用时尽量加括号 程序1: #include<stdio.h> #define SQARE(X) X*X int main() { int  n = 10; int m=SQARE(n); printf("m=%d\n",m); return 0; } 结果: m=100 请按任意键继续. . . 分析:貌似没有出问题,请看下面两个例子 程序2: #include<stdio.h> #define SQARE(X) X*X int 

RHEL6.5上Oracle ACFS与Linux samba一起使用时遇到的bug

RHEL上的Oracle ACFS与linux samba一起使用时遇到的bug 一.环境介绍: cat /etc/issue的结果为: Red Hat Enterprise Linux Server release 6.5 (Santiago) Kernel \r on an \m GI的详细patch信息:仅仅安装了GI的11.2.0.4版本,没有打任何的GI psu,没有打任何的GI patch 二.问题说明: 这是一套rhel6.5的rac,使用的是Oracle GI集群软件,使用了ac