临界区是什么?
要回答这个问题还得先了解一个线程安全问题,每个线程都有自己的栈,而局部变量是存储在栈中的,这就意味着每个线程都有一份自己的"局部变量",如果线程仅仅使用局部变量,那就不存在线程安全问题了,那如果是多个线程共用一个全局变量呢?
下面我们写个简单的案例(他们总喜欢用卖票的例子,这里我就偏偏要用卖花的):
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
int testnum = 10;
DWORD WINAPI ThreadPoc(LPVOID lpParameter)
{
while (testnum>0)
{
printf("还有:%d朵花\n", testnum);
testnum--;
printf("卖出一朵,还有:%d朵\n", testnum);
}
return 0;
}
int main()
{
HANDLE testThread[2];
testThread[0] = CreateThread(NULL, NULL, ThreadPoc, NULL, 0, NULL);
testThread[1] = CreateThread(NULL, NULL, ThreadPoc, NULL, 0, NULL);
CloseHandle(testThread);
system("pause");
}
下面是程序出现的诡异现象:
出现了还有10朵花卖出去一朵还剩下8朵的诡异情况,这种情况就是两个线程同时访问一个全局变量引发的安全问题,因为两个线程来回不停的切换,可能卖花人A去看总数的时候还剩下10朵,但是下一瞬间卖花人B就卖出去一朵,这个时候全局变量减1,而卖花人A还以为剩下的总数是十朵,从而引发的安全问题。
临界区
那么为了解决这个安全问题,引申出我们的主题临界区,那为了解决这个安全问题,如果可以管理多个线程同时使用同一个全局变量的时候,每一次只能有一个线程可以访问到这个全局变量,那么这个全局变量被称为临界资源,而这些被管理的线程被称之为临界区。
实现方式图例:
实现方式,当多个线程同事访问全局变量X的时候,需要先拿到令牌,比如线程1先访问到X,则拿到令牌0,其它2 3再想去访问的时候,就发现令牌变为1了,则只能等待线程1把令牌0归还后再访问全局变量X。
临界区的代码实现
临界区实现之线程锁:
(1)创建全局变量
CRITICAL_SECTION cs;
(2)初始化全局变量
lnitializeCriticalSection(&cs)
(3)实现临界区
EnterCriticalSection(&cs);
//使用临界区资源
LeaveCriticalSection(&cs);
//退出临界区资源
代码使用演示:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
int testnum = 10;
CRITICAL_SECTION cs;
DWORD WINAPI ThreadPoc(LPVOID lpParameter)
{
EnterCriticalSection(&cs);
while (testnum>0)
{
printf("还有:%d朵花\n", testnum);
testnum--;
printf("卖出一朵,还有:%d朵\n", testnum);
}
LeaveCriticalSection(&cs);
return 0;
}
int main()
{
InitializeCriticalSection(&cs);
HANDLE testThread[2];
testThread[0] = CreateThread(NULL, NULL, ThreadPoc, NULL, 0, NULL);
testThread[1] = CreateThread(NULL, NULL, ThreadPoc, NULL, 0, NULL);
CloseHandle(testThread);
system("pause");
}
代码运行结果:
诡异现象不再出现