线程池 与 条件变量


随手写的,并不优雅且可能存在隐藏的问题,仅供参考,谨慎使用


noncopyable.hpp

#ifndef noncopyable_hpp
#define noncopyable_hpp

class noncopyable{

protected:
  noncopyable() = default;
  oncopyable(const noncopyable&) = delete;
  noncopyable& operator=(const noncopyable&) = delete;
};

#endif

t_pool_manage.hpp

#ifndef t_pool_manage_hpp
#define t_pool_manage_hpp

#include <assert.h>
#include <string.h>
#include <thread>
#include <iostream>
#include <sstream>
#include <mutex>
#include <condition_variable>
#include <functional>

#include "noncopyable.hpp"
// #include "blockqueue.hpp"

// 改用普通队列
#include <queue>


using taskFun = std::function<void ()>;

namespace n_thread_pool{
    void thr(int i, 
        std::condition_variable &cv_, 
        std::queue<taskFun>& task_, 
        std::mutex& mtx_, 
        bool& stop_) {
          for (;;){
            std::unique_lock < std::mutex > lck(mtx_);
            cv_.wait(lck, [&]() -> bool {
              printf("notifyed\r\n");
              return !task_.empty() || stop_;});

            if(stop_)
              break;
            auto f = task_.front();
            task_.pop();
            lck.unlock();

            f();
           };
           printf("return\r\n");
        }


class thread_pool: noncopyable  {

public:
  explicit thread_pool(unsigned int initCount = 0) : \
  tCount_(initCount), ths_(nullptr),stop_(false){
    if (!tCount_)
      tCount_ = std::thread::hardware_concurrency();

    ths_ = new std::thread[tCount_];

    assert(ths_ != nullptr);
    for (int i = 0; i < tCount_; i++){
      auto th = new std::thread(
          [&]{
          thr(i, cv_, task_, mtx_, stop_);});

      assert(th != nullptr);
      ths_[i].swap(*th);
     }
  }

  ~thread_pool(){
    stop_ = true;
    cv_.notify_all();
    for (int i = 0; i < tCount_; i++)
      ths_[i].join();
    releaseThs();
  }

  void releaseThs(){
    assert(tCount_ > 0);
    assert(ths_ != nullptr);

    delete [] ths_;
  }

  void addTask(taskFun&& f){
    assert(!stop_);
    std::lock_guard<std::mutex> lck(mtx_);
    task_.push(f);

    telescopicThreadCount();
    cv_.notify_one();
  }

  void telescopicThreadCount(){
    // 根据任务数量伸缩线程数,这里伸缩不能太频繁
    // 最好能根据一段时间的任务进行动态调整
    // 最好根据论文或者依据实验数据来编写

    // 线程数量过多会增大 线程切换开销
    // 另外线程可以减少后续任务的等待时间,但是会增加总执行时间
  }



private:
  unsigned int tCount_;
  std::thread* ths_;
  std::mutex mtx_;
  std::condition_variable cv_;
  // block_queue<taskFun> task_;
  std::queue<taskFun> task_;
  bool stop_;
};

}
#endif

main.cpp


#include <iostream>
#include <stdlib.h>

#include "t_pool_manage.hpp"


void add(int a, int b){
    printf("add: %d\r\n", a + b);
}

int main(){
    {
      n_thread_pool::thread_pool thpool(3);
      thpool.addTask(std::bind(&add, 10, 2));
      system("pause");
    }
    system("pause");
}

后半段是以前转载的 WINAPI 的条件变量用法

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

#define BUFFER_SIZE 10
#define PRODUCER_SLEEP_TIME_MS 500
#define CONSUMER_SLEEP_TIME_MS 2000

LONG Buffer[BUFFER_SIZE];
LONG LastItemProduced;
ULONG QueueSize;
ULONG QueueStartOffset;

ULONG TotalItemsProduced;
ULONG TotalItemsConsumed;

CONDITION_VARIABLE BufferNotEmpty;
CONDITION_VARIABLE BufferNotFull;
CRITICAL_SECTION   BufferLock;

BOOL StopRequested;

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;
}

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;
}

int main ( void )
{
    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);

    puts ("Press enter to stop...");
    getchar();

    EnterCriticalSection (&BufferLock);
    StopRequested = TRUE;
    LeaveCriticalSection (&BufferLock);

    WakeAllConditionVariable (&BufferNotFull);
    WakeAllConditionVariable (&BufferNotEmpty);

    WaitForSingleObject (hProducer1, INFINITE);
    WaitForSingleObject (hConsumer1, INFINITE);
    WaitForSingleObject (hConsumer2, INFINITE);

    printf ("TotalItemsProduced: %u, TotalItemsConsumed: %u\r\n", 
        TotalItemsProduced, TotalItemsConsumed);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值