
本文链接:
当多个线程同时使用相似的资源时,由于是并发执行,不能保证先后顺序.所以假设时一个公共函数被几个线程同时使用会导致该变量值的混乱.
下面来举个简单举例.
假如有一个字符字段变量
char g_charArray[4];
CString szResult;
AfxBeginThread(FunOne,NULL); //FunOne给变量赋值全为S
AfxBeginThread(FunTwo,NULL); //FunTwo也给变量赋值全为B
AfxBeginThread(GetResult,NULL); //得到数组的值,本来希望的值为最后一次赋的值BBBB.但实际结果是不确定的,可能是SBSB,SSBB或者其他
UINT FunOne(LPVOID pParam){ //给变量赋值
for(int i =0; i < 4; i++){
g_charArray[i] = 'S';
Sleep(10);
}
return 0;
}
UINT FunTwo(LPVOID pParam){//得到数组值
for(int i =0; i < 4; i++){
g_charArray[i] = 'B';
Sleep(10);
}
return 0;
}
UINT GetResult(LPVOID pParam){//给变量赋值
szResult = CString(g_charArray);
return 0;
}
为了使公共变量不会被毫无秩序,混乱的修改.我们期望一个线程使用这个函数时其它线程就不能使用,只能等别的线程用完了才用.
于是出现了临界区这说法,相当于把使用到的变量的存储看作一块区域,当某个线程使用时就处于该区域,使用完了离开.当有一个线程处于该区域时其它线程就没法在里面等.临界区的使用如下.
临界区只能用于同一个进程内的线程同步.如果想要多个进程间的线程同步就不能用它了.
CRITICAL_SECTION g_criSection //定义临界区变量
void MainTestFun{
InitializeCriticalSection(&g_criSection); //使用前需要初始化
char g_charArray[4];
CString szResult;
AfxBeginThread(FunOne,NULL);
AfxBeginThread(FunTwo,NULL);
AfxBeginThread(GetResult,); //此时受到的值总是BBBB或者SSSS,哪一个线程拥有临界区不确定.只能确保某一个时间没法有一个线程拥有
//DeleteCriticalSection(&g_criSection); 使用完了临界区就要删除掉,但是在这里这样使用可能会出错.因为需要确保在删除时这个临界区没有再被使用了.所以即使一个类中,一般把它放析构函数中去调用.
}
//在句柄读取的变量的开始调用EnterCriticalSection结束时调用CriticalSection(&g_criSection);
//在后面有用到的所有资源在被使用时其它线程不能使用(不能读也不能改写).其它两个函数FunOne,GetResult按相同的方式添加这两行代码.这里不再写起来了.
UINT FunOne(LPVOID pParam){
EnterCriticalSection(&g_criSection); //表示进入临界区
for(int i =0; i < 4; i++){
g_charArray[i] = 'S';
Sleep(1);
}
LeaveCriticalSection(&g_criSection); //离开临界区
return 0;
}
MFC把里面的操作封装成一个类CCriticalSection,使用函数Lock与Unlock表示开启和离开临界区.上锁和解锁的表述是更符合我们的习惯思维的.
#include "afxmt.h" //需要添加该头文件引用
CCriticalSection g_criSection;
void MainTestFun{
char g_charArray[4];
CString szResult;
AfxBeginThread(FunOne,NULL);
AfxBeginThread(FunTwo,NULL);
AfxBeginThread(GetResult,); //此时受到的值总是BBBB或者SSSS,哪一个线程拥有临界区不确定.只能确保某一个时间没法有一个线程拥有}
//其它两个类也相同加上这两行代码
UINT FunOne(LPVOID pParam){
g_criSection.Lock()//给所有使用的资源上锁
for(int i =0; i < 4; i++){
g_charArray[i] = 'S';
Sleep(1);
}
g_criSection.UnLock(); //给使用的资源解锁
return 0;
}
使线程同步共有4种方法:
1.临界区(critical section)
2.事件(event)
3.信号量(Semaphore)
4.互拆量(Mutex)
其中1临界区是用户对象,所以没很多权限,只能处理同一个进程内的线程同步
而剩下的2,3,4都是内核对象,权限非常大,可以跨进程使用,因此无法处理不同进程间的线程同步问题.
其中的Mutext和临界区适用的画面基本上一样,只不过Mutext是内核对象,而critical section是用户对象
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-121283-1.html
质检局自己去买来检测的是假货