C/C++运行期库
1、概念
在实际的开发过程中,一般使用C/C++运行期函数_beginthreadex代替CreateThread函数。
_beginthreadex首先申请一些用于线程同步的变量,然后调用CreateThread
需要用#include <process.h>头文件
同样,使用_endthreadex代替ExitThread。该函数首先释放用于线程同步的变量,再调用ExitThread。
2、实例
#include <iostream>
#include <Windows.h>
#include <process.h>
using namespace std;
int g_Cnt = 0; // 计数器
BOOL bFlag = FALSE;// 判断是否创建辅助线程
UINT _stdcall ThreadFunc(LPVOID lpParam);
int main()
{
UINT uId[2];
HANDLE h[2];
h[0] = (HANDLE)::_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, &uId[0]);
h[1] = (HANDLE)::_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, &uId[1]);
// 标志创建了辅助线程
bFlag = TRUE;
// 主线程休息1000ms,让出CPU的使用权,让我们的辅助线程有运行的机会
Sleep(1000);
// 主线程运行
bFlag = FALSE;
::WaitForMultipleObjects(2, h, TRUE, INFINITE);
// 关闭句柄
CloseHandle(h[0]);
CloseHandle(h[1]);
printf("g_Cnt = %d\n", g_Cnt);
system("pause");
return 0;
}
UINT _stdcall ThreadFunc(LPVOID lpParam)
{
while (bFlag)
{
g_Cnt++;
}
return 0;
}
3、运行结果
得出来的这个结果不是正确的结果,为什么呢?
4、原因分析
我们所有的计算机指定都是乱序推进的,我们在线程开发中, 必须认为在逻辑上严格限定程序指定序列的推进。
g_Cnt++:运行详解
g_Cnt++是上面三条汇编指令运行的,而且这三条指定有可能会被乱序推进,而且运行过程会被打断。
假定g_Cnt当前值为100,g_Cnt被推进eax这个寄存器中,这个时候eax的值变为100,在线程1中,他会将100与1相加存放在eax中,eax的值变为101,假定这个时候线程1被打断了,开始执行线程2,现在g_Cnt的值在线程1中还未被修改,所以g_Cnt的值还是100,从线程2中从g_Cnt的值读到eax中,所以eax的值从101变为100了,所以只要运行过中被打断,g_Cnt的结果是无法预料的。
如果想让g_Cnt的值圆满运行完毕,我们有且只有一个方法,这个方法就是请让操作系统告诉系统这个线程中的指令序列是不可以被打断的。如果被打断,则会造成运行的结果不可预料。