系统相关
首页 > 系统相关> > Windows提高_2.2第二部分:用户区同步

Windows提高_2.2第二部分:用户区同步

作者:互联网

第二部分:用户区同步

同步和互斥

多线程产生的问题

#include <stdio.h>
#include <windows.h> 
​
// 全局变量,被不同的线程访问和修改
int g_Number = 0;
​
DWORD WINAPI ThreadPro1(LPVOID lpThreadParameter) 
{
    // 为 g_Number 自增 100000 次
    for (int i = 0; i < 100000; i++)
        g_Number++;
    return 0;
}
DWORD WINAPI ThreadPro2(LPVOID lpThreadParameter) 
{
    // 为 g_Number 自增 100000 次
    for (int i = 0; i < 100000; i++)
        g_Number++;
    return 0;
}
int main() 
{
    // 创建两个线程
    HANDLE hThread1 = CreateThread(NULL, NULL, ThreadPro1, NULL, NULL, NULL);
    HANDLE hThread2 = CreateThread(NULL, NULL, ThreadPro2, NULL, NULL, NULL);
​
    // 等待两个线程执行结束
    WaitForSingleObject(hThread1, -1);
    WaitForSingleObject(hThread2, -1);
​
    // 输出修改后的全局变量
    printf("%d", g_Number);
​
    return 0;
}

 

产生问题的原因

mov         eax, dword ptr[Number]
add         eax, 1
mov         dword ptr[Number],eax
; C语言的单条语句被翻译成了多条汇编代码,二线程的切换可能导致多条代码分开执行
mov         eax, dword ptr[Number]    [0]: Number(0)  eax(0)
add         eax, 1                   [0]: Number(0)  eax(1)
mov         dword ptr[Number],eax     [0]: Number(1)  eax(1)

mov         eax, dword ptr[Number]   [1]: Number(1)  eax(1)
add         eax, 1                   [1]: Number(1)  eax(2)
mov         dword ptr[Number],eax     [1]: Number(2)  eax(1)

mov         eax, dword ptr[Number]   [0]: Number(2)  eax(2)
add         eax, 1                   [0]: Number(2)  eax(3) -----------

mov         eax, dword ptr[Number]   [1]: Number(2)  eax(2)
add         eax, 1                   [1]: Number(2)  eax(3)
mov         dword ptr[Number],eax     [1]: Number(3)  eax(3)
mov         eax, dword ptr[Number]   [1]: Number(3)  eax(3)
add         eax, 1                   [1]: Number(3)  eax(4)
mov         dword ptr[Number],eax     [1]: Number(4)  eax(4)

mov         dword ptr[Number],eax     [0]: Number(3)  eax(3) -----------

原子操作(Interlocked...)

for (int i = 0; i < 100000; i++)
{
    // 使用原子操作函数,将自增操作变为不可分割的一条指令
    InterlockedIncrement(&g_Number);
​
    // 以上语句会被翻译成下列单条汇编指令
    // lock inc dword ptr [g_Number]
}

 

临界区(CriticalSection)

// 1. 创建一个临界区(关键段)结构体
CRITICAL_SECTION CriticalSection = { 0 };
​
// 2. 在 【main】 函数中对创建的临界区进行初始化操作
// InitializeCriticalSection(&CriticalSection);
​
DWORD WINAPI ThreadPro1(LPVOID lpThreadParameter)
{
    // 为 g_Number 自增 100000 次
    for (int i = 0; i < 100000; i++)
    {
        // 当有一个线程正在执行代码的时候 
​
        // 同一个线程每进入一次受保护的区域,RecursionCount +1
        // OwningThread 当前被哪一个线程所有
​
        // 3. 使用 EnterCriticalSection 标识需要保护的代码的起始位置
        EnterCriticalSection(&CriticalSection);
        g_Number++;
        // 4. 使用 LeaveCriticalSection 标识需要保护的代码的结束位置
        LeaveCriticalSection(&CriticalSection);
    }
    return 0;
}

 

 

标签:线程,Windows,Number,mov,eax,用户区,dword,2.2,ptr
来源: https://www.cnblogs.com/ltyandy/p/10938192.html