线程同步互斥之信号量对象(Semaphore)

  信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程和进程同时使用共享资源,这与操作系统中的PV操作相同。它指出了同时访问共享资源的线程最大数目。它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。在用CreateSemaphore()创建信号量 时即要同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用资源计数 就会减1,只要当前可用资源计数是大于0的,就可以发出信号量信号。但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最大数目, 不能在允许其他线程的进入,此时的信号量信号将无法发出。线程在处理完共享资源后,应在离开的同时通过ReleaseSemaphore()函数将当前可用资源计数加1。在任何时候当前可用资源计数决不可能大于最大资源计数。 PV操作及信号量的概念都是由荷兰科学家E.W.Dijkstra提出的。信号量S是一个整数,S大于等于零时代表可供并发进程使用的资源实体数,但S小于零时则表示正在等待使用共享资源的进程数。
  P操作申请资源:
S减1; (2)若S减1后仍大于等于零,则进程继续执行; (3)若S减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转入进程调度。
  V操作释放资源:
S加1; (2)若相加结果大于零,则进程继续执行; (3)若相加结果小于等于零,则从该信号的等待队列中唤醒一个等待进程,然后再返回原进程继续执行或转入进程调度。
这些理论知识可以去看相关的书籍,上面解释的比我抄录的解释的更清楚。

#include <iostream>
#include <windows.h>
using namespace std;

static HANDLE g_hSemaphore = INVALID_HANDLE_VALUE;
static int g_Count = 100;
DWORD WINAPI Thread_A(LPVOID lpParamter);
DWORD WINAPI Thread_B(LPVOID lpParamter);

int main(int argc, char** argv)
{
    HANDLE threadA = INVALID_HANDLE_VALUE;
    HANDLE threadB = INVALID_HANDLE_VALUE;
    g_hSemaphore = CreateSemaphore(NULL, 1, 20, TEXT("semaphore"));
    threadA = CreateThread(NULL, 0, Thread_A, NULL, 0, NULL);
    threadB = CreateThread(NULL, 0, Thread_B, NULL, 0, NULL);
    Sleep(5000);
    CloseHandle(threadA);
    CloseHandle(threadB);
    return 0;
}

DWORD WINAPI Thread_A(LPVOID lpParamter)
{
    long count;
    while(1)
    {
        WaitForSingleObject(g_hSemaphore, INFINITE);
        if(g_Count>0)
        {
            cout<<"thread_A:"<<g_Count<<endl;
            ReleaseSemaphore(g_hSemaphore, 1,&count);
            Sleep(1000);
        }
        else
        {       
            break;
        }
    }
    return 0;
}

DWORD WINAPI Thread_B(LPVOID lpParamter)
{
    long count;
    while(1)
    {
        WaitForSingleObject(g_hSemaphore, INFINITE);
        if(g_Count>0)
        {
            cout<<"thread_B:"<<g_Count<<endl;
            ReleaseSemaphore(g_hSemaphore, 1,&count);
            Sleep(1000);
        }
        else
        {

            break;
        }
    }
    return 0;
}

信号量对象的使用步骤(个人看法)
1、CreateSemaphore创建一个信号对象;
2、调用WaitForSingleObject函数等待;
3、使用完后在线程调用ReleaseSemaphore递增信号量的当前资源计数 。

HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount,
LONG lMaximumCount,
LPCTSTR lpName
);
功能:创建一个信号量对象
参数:lpSemaphoreAttributes表示安全控制,一般直接传入NULL。
参数:lInitialCount参数表示初始资源数量。
参数:lMaximumCount参数表示最大并发数量。
参数:lpName 参数表示信号量的名称,传入NULL表示匿名信号量。
返回值:成功返回信号量对象的句柄,失败返回NULL

函数功能:BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
LPLONG lpPreviousCount
);
功能:递增信号量的当前资源计数
参数:hSemaphore参数是信号量的句柄。
参数:lReleaseCount参数表示增加个数,必须大于0且不超过最大资源数量。
参数:lpPreviousCount 数可以用来传出先前的资源计数,设为NULL表示不需 要传出。
返回值:成功为true,否则为false

  以上是信号量对象那的基本用法,更多用法可以去查阅相关的资料!

猜你喜欢

转载自blog.csdn.net/u013421892/article/details/47837907