线程不安全
多个线程操作同一个变量,会有线程不安全的问题,程序示例
#include <Windows.h>
#include <stdio.h>
int gNum = 0;
DWORD WINAPI testProc(LPVOID pParam)
{
for (int i = 0; i < 10000; i++)
{
gNum++; //这样操作线程不安全
}
return 0;
}
int main()
{
DWORD nId = 0;
HANDLE hThreads[2];
hThreads[0] = CreateThread(NULL, 0, testProc, NULL, 0, &nId); //直接启动
hThreads[1] = CreateThread(NULL, 0, testProc, NULL, 0, &nId); //直接启动
WaitForMultipleObjects(2, hThreads, true, INFINITE);
printf("num = %d\n", gNum);
return 0;
}
说明:
- 输出结果19812,不是20000,这是线程不安全造成的.
- 如果输出结果为20000,就把循环次数加大,就会出现错误结果.
线程的原子锁
原子锁可以解决不同线程使用同一个变量的线程安全问题.程序示例.
#include <Windows.h>
#include <stdio.h>
int gNum = 0;
DWORD WINAPI testProc(LPVOID pParam)
{
for (int i = 0; i < 10000; i++)
{
//gNum++; //这样操作线程不安全
InterlockedIncrement((long*)&gNum); //线程安全方式
}
return 0;
}
int main()
{
DWORD nId = 0;
HANDLE hThreads[2];
hThreads[0] = CreateThread(NULL, 0, testProc, NULL, 0, &nId); //直接启动
hThreads[1] = CreateThread(NULL, 0, testProc, NULL, 0, &nId); //直接启动
WaitForMultipleObjects(2, hThreads, true, INFINITE);
printf("num = %d\n", gNum);
return 0;
}
说明:
- 原子锁执行效率很高.
- 只支持运算相关的操作,有一定的局限性.
- 针对不同运算,提供不的函数.
线程互斥
程序示例
#include <Windows.h>
#include <stdio.h>
HANDLE gMutex;
DWORD WINAPI testProc(LPVOID pParam)
{
char* pChar = (char*)pParam;
while (true)
{
WaitForSingleObject(gMutex, INFINITE); //使用互斥量来保证线程安全
for (int i = 0; i < strlen(pChar); i++)
{
printf("%c", pChar[i]);
Sleep(100);
}
printf("\n");
ReleaseMutex(gMutex);
}
}
int main()
{
gMutex = CreateMutex(NULL, false, NULL);
DWORD nId = 0;
HANDLE hThreads[2];
const char* pChar = "********";
hThreads[0] = CreateThread(NULL, 0, testProc, const_cast<char*>(pChar), 0, &nId); //直接启动
pChar = "--------";
hThreads[1] = CreateThread(NULL, 0, testProc, const_cast<char*>(pChar), 0, &nId); //直接启动
getchar();
CloseHandle(gMutex);
return 0;
}
说明
- 通过原子锁和互斥量的方式来保证线程安全,都是互斥的方式.
- 针对运算符的互斥,原子量的效率高.