多线程同步


本文主要讲了用户模式下的线程同步机制,用户模式下的同步最大的好处是速度快。此外还有内核状态下的同步机制将放在写一篇博客中讲述!

原子访问

  • 指的是一个线程在访问某个资源的同时能够保证没有其他线程会在同一时刻访问同一资源。
    Interlocked系列的函数可以保证是原子操作。


高级线程同步

  • 当线程想要访问某一共享资源的时候,线程必须调用系统函数,将线程想要访问的东西作为参数传递给函数。如果操作系统检测到资源可以被访问,那么这个函数会立即返回。这样线程就编程可调度状态。如果无法访问该共享资源,那么系统会将线程切换到等待状态,使线程变得不可调度,从而避免线程浪费CPU的时间。


关键代码段

  • 这种方式让多行代码以原子的方式对资源进行操控。
    1
    2
    3
    4
    5
    6
    CRITICAL_SECTION g_cs 	//初始化关键代码段结构
    InitializeCriticalSection(g_cs); //初始化
    EnterCriticalSection(&g_cs); //进入关键代码段
    ...
    LeaveCriticalSection(&g_cs); //离开关键代码段
    DeleteCriticalSection(g_cs); //删除

关键段与旋转锁

  • 当线程试图进入一个关键段,但这个关键段正被另一个线程占用的时候,函数会立即把调用线程切换到等待状态。这意味着线程必须从用户模式切换到内核模式(消耗大约1000个CPU周期)。这个切换的开销非常大。在配有多处理器的机器中,当前占用资源的线程可能在另一个线程完全切换到内核状态前就释放了占用的资源。如果真发生这种情况,那么会消耗大量的CPU周期。
    因此在关键代码段中加入旋转锁来解决此问题。
1
BOOL InitializeCriticalSectionAndSpinCount(PCRITICAL_SECTION pcs, DWORD dwSpinCount);//dwSpinCount 表示旋转锁循环的次数


Slim读/写锁

  • SRWLock允许我们区分那些想要读取资源值的线程(读取者线程)和想要更新资源值的线程(写入者线程)。让所有读取者线程同一时刻访问资源是可行的,因为不会破坏数据。写入者线程应该独占资源的访问权,任何其他读取者线程与写入者线程都不允许访问该资源。这就是SRWLock锁的关不内容。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    VOID InitializeSRWLock(PSRWLOCK SRWLock);//初始化

    //写入者线程访问
    VOID AcquireSRWLockExclusive(PSRWLOCK SRWLock); //读
    VOID ReleaseSRWLockExclusive(PSRWLOCK SRWLock); //释放

    //读取者线程访问
    VOID AcquireSRWLockShared(PSRWLOCK SRWLock); //读
    VOID ReleaseSRWLockShared(PSRWLOCK SRWLock); //释放