為什么要對多線程進行加鎖操作呢


一.如果不加鎖,會怎么樣?

可能會發生數據競爭,造成數據錯亂.

例子:

本來想要的結果n=0,但是執行發現n的值不為0,而且有多種取值.究其原因,是因為多個線程之間會發生數據競爭,導致CPU線程調度時出現問題,不能夠保證線程內執行代碼的原子操作.我發現string str = "hello";這一句是必要的,不然它就不會出現n不為0的現象.(有待進一步研究)

注意,如果要所有子線程執行完畢后,再執行主線程.要有WaitForMultipleObjects操作.

#include "windows.h"
#include <iostream>using namespace std;const int ThreadNum = 50;
int g_Num = 0;
DWORD WINAPI ThreadFun(void * param)
{
    for (int i = 0; i < 100; i++)
    {
        g_Num = g_Num+1;
        string str = "hello";
        g_Num = g_Num-1;
    }
    return 0;
}
int main()
{
    DWORD lpThread[ThreadNum];
    HANDLE h[ThreadNum];
    for (int i = 0; i <ThreadNum; i++)
    {
         h[i] = CreateThread(NULL, 0, ThreadFun, NULL, 0, &lpThread[i]);
    }
    WaitForMultipleObjects(ThreadNum, h, TRUE, INFINITE); //等待所有的子線程執行完畢.
    int n = g_Num;
    cout << "n:" << n << endl;
    return 0;
}

二.加鎖后的情形

WaitForMultipleObjects是必須的,一開始忘記了使用這個,導致在EnterCriticalSection處報錯,猜測是主線程沒有等子線程執行完畢就結束了程序.為了驗證猜想,將WaitForMultipleObjects注釋掉,
在子函數中打印,發現確實是這個原因.
加鎖后每次n打印出來的都是0了.
#include "windows.h"
#include <iostream>
using namespace std;
const int ThreadNum = 50;

CRITICAL_SECTION g_Cs;
int g_Num = 0;
DWORD WINAPI ThreadFun(void * param)
{
    for (int i = 0; i < 100; i++)
    {
        EnterCriticalSection(&g_Cs);
        g_Num = g_Num+1;
        string str = "hello";
        g_Num = g_Num-1;
        LeaveCriticalSection(&g_Cs);
    }
    return 0;
}

int main()
{
    InitializeCriticalSection(&g_Cs);
    DWORD lpThread[ThreadNum];
    HANDLE h[ThreadNum];
    for (int i = 0; i <ThreadNum; i++)
    {
        h[i] = CreateThread(NULL, 0, ThreadFun, NULL, 0, &lpThread[i]);
    }
    WaitForMultipleObjects(ThreadNum, h, TRUE, INFINITE); //等待所有的子線程執行完畢.
    int n = g_Num;
    cout << "n:" << n << endl;
    DeleteCriticalSection(&g_Cs);
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM