• 为什么要对多线程进行加锁操作呢


    一.如果不加锁,会怎么样?

    可能会发生数据竞争,造成数据错乱.

    例子:

    本来想要的结果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;
    }
    新战场:https://blog.csdn.net/Stephen___Qin
  • 相关阅读:
    HDFS 2.X新特性
    kettle的系列教程
    Kettle基本使用
    MySQL流程控制结构
    MySQL函数
    MySQL存储过程和函数
    MySQL变量
    MySQL视图
    TCL(事务控制语言)
    MySQL标识列(自增长列)
  • 原文地址:https://www.cnblogs.com/Stephen-Qin/p/12702487.html
Copyright © 2020-2023  润新知