• 线程同步互斥之信号量对象(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

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

  • 相关阅读:
    Codeforces Round #629 (Div. 3) (A ~ F)
    st表
    Educational Codeforces Round 81 (Rated for Div. 2)
    hihocoder#1996 : 01匹配
    P2056 [ZJOI2007]捉迷藏
    P2495 [SDOI2011]消耗战
    GUETOJ1335
    优先队列重载比较运算
    CCF认证201909-4 推荐系统
    P3178 [HAOI2015]树上操作
  • 原文地址:https://www.cnblogs.com/huiz/p/9610676.html
Copyright © 2020-2023  润新知