zoukankan      html  css  js  c++  java
  • 线程条件变量,一次性初始化

    以SDK的生产者和消费者为例,两个是一个循环关系.

    生产者的职责:

    1.负责生产产品,如果产品的产量达到最高量了,就停止生产(没有消费者用,当然停掉了),即生产线暂时停工
    2.当有消费者购买时,未达到最高产品数量的时候,则继续生产.

    以上可以看到生产者生产东西是有条件的,即有人消费(废话,卖东西肯定得有人买了,有人购买就是生产的触发条件)

    归纳为

    生产者做了以下事情

    1.东西卖不出去,停止生产
    2.通知消费者,我有货快来买
    3.有消费者买了产品,继续生产到最高产品数量

    三者不断循环

    同理消费者的逻辑也相似

    1.没有产品,停止使用
    2.通知生产者,东西卖完了,赶紧补货
    3.生产者生产好产品,消费者继续使用

    三者不断循环

    那么假设生产者和消费者,各自为一个线程,当某些条件满足时就会阻塞自己(如东西卖不出去,停止生产;没有产品,停止使用),当打破这些条件时则继续执行,在现实生活中这很容易理解,换成代码比较晦涩.下面来看代码

    先定义三个变量

    CONDITION_VARIABLE BufferNotEmpty;
    CONDITION_VARIABLE BufferNotFull;
    CRITICAL_SECTION   BufferLock;
    

    必须要对变量进行初始化调用,然后有1个生产者和2个消费者,条件变量依赖于临界区(CRITICAL_SECTION)

    InitializeConditionVariable (&BufferNotEmpty);
    InitializeConditionVariable (&BufferNotFull);
    
    InitializeCriticalSection (&BufferLock);
    
    DWORD id;
    HANDLE hProducer1 = CreateThread (NULL, 0, ProducerThreadProc, (PVOID)1, 0, &id);
    HANDLE hConsumer1 = CreateThread (NULL, 0, ConsumerThreadProc, (PVOID)1, 0, &id);
    HANDLE hConsumer2 = CreateThread (NULL, 0, ConsumerThreadProc, (PVOID)2, 0, &id);
    

    来看生产者代码:

    DWORD WINAPI ProducerThreadProc (PVOID p)
    {
        ULONG ProducerId = (ULONG)(ULONG_PTR)p;
    
        while (true)
        {
            // Produce a new item.
    
            Sleep (rand() % PRODUCER_SLEEP_TIME_MS);
    
            ULONG Item = InterlockedIncrement (&LastItemProduced);
    
            EnterCriticalSection (&BufferLock);
    
            while (QueueSize == BUFFER_SIZE && StopRequested == FALSE)
            {
                // Buffer is full - sleep so consumers can get items.
                SleepConditionVariableCS (&BufferNotFull, &BufferLock, INFINITE);
            }
    
            if (StopRequested == TRUE)
            {
                LeaveCriticalSection (&BufferLock);
                break;
            }
    
            // Insert the item at the end of the queue and increment size.
    
            Buffer[(QueueStartOffset + QueueSize) % BUFFER_SIZE] = Item;
            QueueSize++;
            TotalItemsProduced++;
    
            printf ("Producer %u: item %2d, queue size %2u\r\n", ProducerId, Item, QueueSize);
    
            LeaveCriticalSection (&BufferLock);
    
            // If a consumer is waiting, wake it.
    
            WakeConditionVariable (&BufferNotEmpty);
        }
    
        printf ("Producer %u exiting\r\n", ProducerId);
        return 0;
    }
    

    当数量等于BUFFER_SIZE则罢工,否则的话生产出产品就通知消费者有货

    while (QueueSize == BUFFER_SIZE && StopRequested == FALSE)
    {
        // Buffer is full - sleep so consumers can get items.
        SleepConditionVariableCS (&BufferNotFull, &BufferLock, INFINITE);
    }
    
    // If a consumer is waiting, wake it.
    
    WakeConditionVariable (&BufferNotEmpty);
    

    消费者也是如此,没货就等待,当用完一个产品就通知生产者继续生产

    while (QueueSize == 0 && StopRequested == FALSE)
    {
        // Buffer is empty - sleep so producers can create items.
        SleepConditionVariableCS (&BufferNotEmpty, &BufferLock, INFINITE);
    }
    
    WakeConditionVariable (&BufferNotFull);
    
    DWORD WINAPI ConsumerThreadProc (PVOID p)
    {
        
        ULONG ConsumerId = (ULONG)(ULONG_PTR)p;
    
        while (true)
        {
            EnterCriticalSection (&BufferLock);
    
            while (QueueSize == 0 && StopRequested == FALSE)
            {
                // Buffer is empty - sleep so producers can create items.
                SleepConditionVariableCS (&BufferNotEmpty, &BufferLock, INFINITE);
            }
    
            if (StopRequested == TRUE && QueueSize == 0)
            {
                LeaveCriticalSection (&BufferLock);
                break;
            }
    
            // Consume the first available item.
    
            LONG Item = Buffer[QueueStartOffset];
    
            QueueSize--;
            QueueStartOffset++;
            TotalItemsConsumed++;
    
            if (QueueStartOffset == BUFFER_SIZE)
            {
                QueueStartOffset = 0;
            }
    
            printf ("Consumer %u: item %2d, queue size %2u\r\n", 
                ConsumerId, Item, QueueSize);
    
            LeaveCriticalSection (&BufferLock);
    
            // If a producer is waiting, wake it.
    
            WakeConditionVariable (&BufferNotFull);
    
            // Simulate processing of the item.
    
            Sleep (rand() % CONSUMER_SLEEP_TIME_MS);
        }
    
        printf ("Consumer %u exiting\r\n", ConsumerId);
        return 0;
    }
    

    附带Windows核心编程第5版(采用新api)以前的线程池资料

    http://wenku.baidu.com/view/3df5000d6c85ec3a87c2c5c0.html

    一次性初始化

    以保证线程在调用资源时,确保资源已经被初始化,并且只初始化一次

    InitHandleFunction 函数将只会触发一次,初始化的对象估计会与INIT_ONCE对象关联起来

    // Global variable
     INIT_ONCE g_InitOnce;
     
     BOOL CALLBACK InitHandleFunction (
         PINIT_ONCE InitOnce,
         PVOID Parameter,
         PVOID *lpContext)
     {
     
       HANDLE hEvent;
     
       hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
     
       if (NULL == hEvent)
       {
         return FALSE;
       }
       else
       {
         *lpContext = hEvent;
         return TRUE;
       }
     }
     
     HANDLE OpenEventHandleSync()
     {
       PVOID lpContext;
       BOOL  bStatus;
       
       bStatus = InitOnceExecuteOnce(&g_InitOnce,
                                     InitHandleFunction,
                                     NULL,
                                     &lpContext);
     
       if (bStatus)
       {
         return (HANDLE)lpContext;
       }
       else
       {
         return (INVALID_HANDLE_VALUE);
       }
     }
    

    异步初始化:

    其甚至没有回调函数,并且前后有两个InitOnceBeginInitialize函数,用InitOnceComplete来通知初始化完毕

    // Global variable
      INIT_ONCE g_InitOnce;
      
      HANDLE OpenEventHandleAsync()
      {
        PVOID  lpContext;
        BOOL   fStatus;
        BOOL   fPending;
        HANDLE hEvent;
        
        fStatus = InitOnceBeginInitialize(&g_InitOnce,
                                          INIT_ONCE_ASYNC,
                                          &fPending,
                                          &lpContext);  
      
        if (!fStatus)
        {
          return (INVALID_HANDLE_VALUE);
        }
      
        // Initialization has already completed.
        if (!fPending)
        {
          return (HANDLE)lpContext;
        }
      
        hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
        if (NULL == hEvent)
        {
          return (INVALID_HANDLE_VALUE);
        }
      
      
        fStatus = InitOnceComplete(&g_InitOnce,
                                   INIT_ONCE_ASYNC,
                                   (PVOID)hEvent);
      
        if (fStatus)
        {
          return hEvent;
        }
        
        // Initialization has already completed. Free the local event.
        CloseHandle(hEvent);
      
      
        // Retrieve the final context data.
        fStatus = InitOnceBeginInitialize(&g_InitOnce,
                                          INIT_ONCE_CHECK_ONLY,
                                          &fPending,
                                          &lpContext);
      
        if (fStatus && !fPending)
        {
          return (HANDLE)lpContext;
        }
        else
        {
          return INVALID_HANDLE_VALUE;
        }
      }
    
    

    参考:
    http://msdn.microsoft.com/zh-cn/magazine/cc163405.aspx#S3

  • 相关阅读:
    文件操作与函数
    编码格式
    if、while、for快速掌握
    运算符、数据类型、数据结构
    正则表达式
    面向对象--属性
    面向对象--对象的创建
    函数的内置属性
    类型检查
    函数表达式 及 闭包
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/2050553.html
Copyright © 2011-2022 走看看