随手写的,并不优雅且可能存在隐藏的问题,仅供参考,谨慎使用
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;
}