C++ 线程池【生产者消费者模型】

经典的C++ 线程池模型。

【ThreadPool.h】

#pragma once

#include <iostream>
#include <queue>
#include <thread>
using namespace std;

template <class T>
class ThreadPool
{
	private:
		int _threadCount;
		queue<T> _queue;
		pthread_mutex_t _mlock;
		pthread_cond_t _cond;
		static ThreadPool<T> *_instance;

	private:
		ThreadPool(int threadCount = 3)
			: _threadCount(threadCount)
		{
			pthread_mutex_init(&_mlock,nullptr);
			pthread_cond_init(&_cond,nullptr);
		}
		ThreadPool(const ThreadPool<T> &) = delete;
		ThreadPool& operator=(const ThreadPool<T>&)=delete; //禁用拷贝构造和赋值运算符重载
		void Lock()
		{
			pthread_mutex_lock(&_mlock);
		}
		void Unlock()
		{
			pthread_mutex_unlock(&_mlock);
		}
		void Pop(T *t)
		{
			*t = _queue.front();
			_queue.pop();
		}
		bool Empty()
		{
			return _queue.empty();
		}

		static void *Handler(void *arg)
		{
			ThreadPool<T> *obj = (ThreadPool<T> *)arg;
			pthread_detach(pthread_self());
			while (true)
			{
				obj->Lock();
				//先获取任务,没有任务挂起
				while (obj->Empty())
				{
					pthread_cond_wait(&obj->_cond, &obj->_mlock);//阻塞后同时会释放_mlock
				}
				T t;
				obj->Pop(&t);
				obj->Unlock();
				//处理任务
				t();
			}
		}
		void Init()
		{
			pthread_t tid;
			for (int i = 0; i < _threadCount; i++)
			{
				pthread_create(&tid, nullptr, Handler, this);
			}
		}

	public:
		~ThreadPool()
		{
			pthread_mutex_destroy(&_mlock);
			pthread_cond_destroy(&_cond);
		}

		static ThreadPool<T> *GetInstance()
		{
			static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
			if (_instance == nullptr)
			{
				pthread_mutex_lock(&mtx);
				if (_instance == nullptr)
				{
					_instance = new ThreadPool<T>;
					_instance->Init();
				}
				pthread_mutex_unlock(&mtx);
			}
			return _instance;
		}

		void Push(const T &t)
		{
			Lock();
			_queue.push(t);
			Unlock();
			//此时可能所有的线程已经全部休眠,需要唤醒一下
			pthread_cond_signal(&_cond);
		}
};

template <class T>
ThreadPool<T> *ThreadPool<T>::_instance = nullptr;

【main.cpp】

#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include "ThreadPool.h"

pthread_mutex_t taskMutex;

class Task
{
	private:
		int a;
		int b;

	public:
		Task()
		{}
		Task(int x, int y)
			: a(x), b(y)
		{}

		void operator()()
		{
			pthread_mutex_lock(&taskMutex);
			cout<<"线程ID:"<<pthread_self()<<","<< a << "+" << b << "=" << a + b << endl;
			pthread_mutex_unlock(&taskMutex);
		}
};

void *Produce(void *arg)
{
	pthread_detach(pthread_self());
	ThreadPool<Task> *pool = (ThreadPool<Task> *)arg;
	while (true)
	{
		Task t(rand() % 10, rand() % 10);
		sleep(1);
		pool->Push(t);
	}
}

int main()
{
	pthread_mutex_init(&taskMutex, nullptr);
	srand((long long)time(nullptr));
	pthread_t tid;
	ThreadPool<Task> *pool = ThreadPool<Task>::GetInstance();
	for (int i = 0; i < 5; i++)
	{
		pthread_create(&tid, nullptr, Produce, pool);
	}
	while (1);
	return 0;
}

 【Makefile】

src=$(wildcard *.cpp)
obj=$(patsubst %.cpp, %, $(src))

CFLAGS+=-std=c++11 -pthread
INC+=-I./
ALL:$(obj)
%:%.cpp
	g++ $< -o $@ $(INC) $(CFLAGS)
.PHONY:clean ALL
clean:
	-rm -rf $(obj)

运行结果:

 

这个例子用到的知识非常多,包括:类模板、单例模式、STL中的队列、条件变量、互斥锁、以及多线程等,值得细看

主要描述了,main函数创建了5个生产者线程,不断向queue中加入task。

生产者同样也有5个线程,5个线程不间断的去询问队列,是否有任务可做,如果没有,则使用pthread_cond_wait()阻塞当前线程。

pthread_cond_wait():

        用于阻塞当前线程,等待别的线程使用pthread_cond_signal()pthread_cond_broadcast来唤醒它 pthread_cond_wait() 必须与pthread_mutex配套使用。pthread_cond_wait()函数一进入wait状态就会自动release mutex。当其他线程通过pthread_cond_signal()pthread_cond_broadcast,把该线程唤醒,使pthread_cond_wait()通过(返回)时,该线程又自动获得该mutex

        使用t() 去处理队列中的任务,这个是重载了()运算符。

此代码忘记在哪里看到的了,今天偶尔翻到,这里记录一下,如有侵权请聊系我删除。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
生产者消费者模型是一种并发编程模型,用于解决生产者消费者之间的数据交换问题。在这个模型中,生产者负责生产数据,消费者负责消费数据。 模型的实现通常涉及到共享资源(如队列)和同步机制(如锁、条件变量)。生产者消费者通过共享的队列进行通信。当队列为空时,消费者将等待,直到有数据可供消费。当队列满时,生产者将等待,直到有空间可供生产。 在你提供的引用中,生产者线程和消费者线程使用了互斥锁和条件变量来实现同步。当消费者线程获取锁后,如果队列为空,则会进入等待状态,并释放锁。此时生产者线程可以获取锁,并判断队列是否为空,如果为空,则进入等待状态并释放锁。当生产者线程生产了产品后,会通过条件变量通知消费者线程可以消费了。消费者线程收到通知后,需要获取锁才能进行消费。 总结一下生产者消费者模型的步骤: 1. 定义共享队列作为生产者消费者之间的数据交换通道。 2. 定义互斥锁,确保同时只有一个线程能够访问共享资源(即队列)。 3. 定义条件变量,用于线程间的通信。 4. 生产者线程获取互斥锁,判断队列是否已满,如果满则等待,否则生产数据并将其放入队列。 5. 如果消费者线程获取互斥锁,判断队列是否为空,如果为空则等待,否则消费数据并从队列中移除。 6. 在适当的时候,使用条件变量通知等待中的线程继续执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值