加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

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

发布时间:2020-12-14 01:37:37 所属栏目:Windows 来源:网络整理
导读:第二部分:用户区同步 同步和互斥 同步:就是按照一定的顺序执行不同的线程 互斥:当一个线程访问某一资源的时候,其它线程不能同时访问 多线程产生的问题 #include stdio.h #include windows.h ? // 全局变量,被不同的线程访问和修改 int g_Number = 0 ;?D

第二部分:用户区同步

同步和互斥

  • 同步:就是按照一定的顺序执行不同的线程

  • 互斥:当一个线程访问某一资源的时候,其它线程不能同时访问

多线程产生的问题

#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);
    HANDLE hThread2 = CreateThread(NULL,ThreadPro2,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...)

  • 特点:将一条语句转换成了具有同等功能的单条汇编指令 lock inc dword ptr [Number]

  • 缺点:只能给单个整数类型(4/8)进行保护,不能给使一段代码变成原子操作

  • 函数:

    • InterlockedXXX

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

?

临界区(CriticalSection)

  • 特点:拥有线程拥有者的概念,同一个线程可以不断的重新进入临界区,但是进入了多少次,就要退出多少。

  • 缺点:一旦拥有临界区的线程崩溃,那么所有等待临界区的线程就会产生死锁。

  • 函数:

    • 初始化: InitializeCriticalSection

    • 保护:EnterCriticalSection

    • 结束保护 :LeaveCriticalSection

    • 删除:DeleteCriticalSection

// 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;
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读