线程的互斥和同步(5)- Windows的信号量Semaphore

信号量也是线程间同步常用的手段之一。举个例子,比如我们要去餐馆吃饭,这家餐馆一共有4个位置,我们一共是6个人。那么就会4个人先去吃饭,等他们吃完了,剩下的2个人再去吃饭,如果再来人则需要判断是否有空位置,如果有直接坐下吃饭,如果没有则需要等待。

这里的每一个顾客就相当于一个线程,而通知你排队叫号进餐的那个服务员就是我们的信号量。信号量可以有效的保证我们多个线程并发执行。

对于信号量,我们经常使用的函数如下:

  • CreateSemaphore (LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount,LONG lMaximumCount, LPCWSTR lpName) // 创建信号量
  • ReleaseSemaphore (HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount) // 指定信号量增加指定的值
  • WaitForSingleObject (HANDLE hHandle, DWORD dwMilliseconds) // 等待指定信号量有信号

1. CreateSemaphore 函数,创建信号量
  • 参数 lpSemaphoreAttributes : 表示安全属性,一般设置为 nullptr 表示默认安全属性。
  • 参数 lInitialCount : 表示指定初始化资源的个数。
  • 参数 lMaximumCount : 表示最大资源数。如果使用函数 ReleaseSemaphore ,不断增加资源数,资源数最大不能超过这个数值。此值必须大于0。
  • 参数 lpName : 表示名称。可以设置为nullptr。
  • 返回值: 创建成功返回 semaphore 句柄,不成功返回 nullptr
2. ReleaseSemaphore 函数,指定信号量增加指定的值
  • 参数 hSemaphore : 信号量句柄。
  • 参数 lReleaseCount : 需要增加的资源数量。
  • 参数 lpPreviousCount : 返回上一次资源数,如果不需要可以设置为 nullptr
3. WaitForSingleObject 函数,等待指定信号量有信号

关于该函数的介绍可参照:线程的互斥和同步(3)- Windows的互斥锁


下面是关于信号量的简单示例:

这里同样使用的 CThread ,头文件:

#include "CThread.h"
class SemaphoreThread : public CThread
{
public:
    void run(void) override;

    // 创建信号量
    static void createSemaphore(int number);
};

源文件:

#include <iostream>
#include <atomic>

HANDLE g_semphore;
std::atomic<int> number(0);
void SemaphoreThread::run(void)
{
    if (::WaitForSingleObject(g_semphore, INFINITE) == WAIT_OBJECT_0)
    {
        number++;
        std::cout << "Custom " << ::GetCurrentThreadId() << ", Sit Down!" \
            << " Your are " << number << "th Cunstom." << std::endl;

        ::Sleep(300);

        ::ReleaseSemaphore(g_semphore, 1, nullptr);
    }
    else
        std::cout << "Error!" << std::endl;
}

void SemaphoreThread::createSemaphore(int number)
{
    // 创建信号量
    g_semphore = ::CreateSemaphore(nullptr, number, number, nullptr);
}

调用部分:

int main(int argc, char** argv)
{
    // 四个资源 - 餐馆4个座位
    SemaphoreThread::createSemaphore(4);
    // 创建6个线程,6个客人排队等待4个座位
    SemaphoreThread thread[6];
    for (int i = 0; i < 6; ++i)
        thread[i].start();

    for (int i = 0; i < 6; ++i)
        thread[i].wait();

    system("pause");
    return 0;
}

这个示例中,模拟6个客人排队等待4个座位。

执行结果:
Custom 8932, Sit Down! Your are 1th Cunstom.
Custom 9760, Sit Down! Your are 2th Cunstom.
Custom 7836, Sit Down! Your are 3th Cunstom.
Custom 13736, Sit Down! Your are 4th Cunstom.
Custom 20900, Sit Down! Your are 5th Cunstom.
Custom 9308, Sit Down! Your are 6th Cunstom.

不会飞的纸飞机
扫一扫二维码,了解我的更多动态。

下一篇文章:线程的互斥和同步(6)- Qt的信号量QSemaphore