线程
线程是进程中真正执行任务的基本单位
一个进程由多个称为线程的执行单元组成
同一进程的多个线程共享同样的代码和全局数据,共享整个虚拟地址空间,栈区通常是不共享的
线程同步
当多个线程共享相同内存时,需要确保每个线程看到一致的数据视图
如果每个线程使用的变量,其他线程都不会读取和修改
或变量只是只读的,那么就不会出现一致性问题
但当一个进程可以修改变量且其他线程也可以读取或修改,就需要线程同步,使用锁,可以保证同一时间只允许一个线程访问该变量
如果操作是原子操作,也就是操作只需要一个存储器周期,那么就不存在竞争,也就不需要同步
线程池
动态创建线程比较耗费时间,将导致较慢的响应
线程池是服务器预先创建好的一组线程,当有请求到来时,主线程选择线程池的某一个线程来为之服务,这样可以提高效率
通常的作法是所有线程通过一个共享的工作队列来同步,当工作队列为空时,工作线程都阻塞在该工作队列上。当有新的任务时,主线程将任务添加进工作队列,唤醒工作线程,某个工作线程处理任务,其他工作线程将继续等待。
代码
threadpool.h
#pragma once
#include <pthread.h>
#include <functional>
#include <deque>
class Threadpool
{
typedef std::function<void()> Task;
public:
static void* threadfunc(void* threadData);//线程运行函数
Threadpool(int threadnum=4);
~Threadpool();
void addtask(const Task &task);//任务入队
int size();//任务队列长度
Task poll();//弹出任务
private:
pthread_t *threads_;
int threadnum_;
bool isrun_;//池子是否处于活动状态,当调用析构函数时置为false
std::deque<Task> taskqueue_;
pthread_mutex_t mutex_;
pthread_cond_t cond_;
};
threadpool.cpp
#include "threadpool.h"
#include <stdio.h>
#include <assert.h>
void *Threadpool::threadfunc(void *threadData)
{
pthread_t tid=pthread_self();
Threadpool* pool=static_cast<Threadpool*>(threadData);
while(pool->isrun_){
Threadpool::Task task=pool->poll();
if(!task){
printf("thread %lu will exit\n",tid);
break;
}
assert(task);
task();
}
return nullptr;
}
Threadpool::Threadpool(int threadnum) : threadnum_(threadnum), isrun_(true)
{
pthread_mutex_init(&mutex_,NULL);
pthread_cond_init(&cond_,NULL);
threads_=new pthread_t[threadnum_];
for(int i=0;i<threadnum_;i++){
pthread_create(&threads_[i],NULL,threadfunc,this);//创建线程
}
}
Threadpool::~Threadpool()
{
if(!isrun_)
return;
isrun_=false;
pthread_cond_broadcast(&cond_);//唤醒所有工作线程
for(int i=0;i<threadnum_;i++){
pthread_join(threads_[i],NULL);//等待工作线程退出,回收资源
}
delete []threads_;
threads_=nullptr;
pthread_mutex_destroy(&mutex_);
pthread_cond_destroy(&cond_);
}
void Threadpool::addtask(const Task &task)
{
pthread_mutex_lock(&mutex_);
taskqueue_.push_back(task);
pthread_mutex_unlock(&mutex_);
pthread_cond_signal(&cond_);//任务入队后唤醒工作线程,注意不一定只唤醒一个
}
int Threadpool::size()
{
pthread_mutex_lock(&mutex_);
int size=taskqueue_.size();
pthread_mutex_unlock(&mutex_);
return size;
}
Threadpool::Task Threadpool::poll()
{
Task task=NULL;
pthread_mutex_lock(&mutex_);
while(taskqueue_.empty()&&isrun_)
pthread_cond_wait(&cond_,&mutex_);//任务队列空且活动状态,阻塞工作线程
if(!isrun_){//非活动状态直接返回
pthread_mutex_unlock(&mutex_);
return task;
}
assert(!taskqueue_.empty());
task=taskqueue_.front();
taskqueue_.pop_front();
pthread_mutex_unlock(&mutex_);
return task;
}
main.cpp
#include <iostream>
#include <string>
#include <unistd.h>
#include "threadpool.h"
using namespace std;
void print(std::string str){
std::cout<<str<<std::endl;
}
void test()
{
std::cout<<"hi"<<std::endl;
}
int main(){
Threadpool *pool=new Threadpool();
std::function<void()> func=std::bind(print,"hello world");
pool->addtask(func);
func=test;
pool->addtask(func);
sleep(1);//保证工作线程运行完整,主线程不会提前结束
delete pool;
return 0;
}
结果
参考
UNIX网络编程 卷1:套接字联网API 第3版
Linux高性能服务器编程——游双