线程、锁、线程池
来源:互联网 发布:验血单哪项数据看男女 编辑:程序博客网 时间:2024/05/01 18:17
写在前面
最近看了线程池的原理,也学到不少知识,现做出总结,同时也实现了自己的线程池。
线程(Thread)
在任何一个时间点,线程有2种状态(这里与新建、就绪、执行、阻塞和死亡5种状态是两类不同的概念):
- 可结合的(joinable)
thread.join,创建线程有回收和杀死线程的权利,创建线程会被阻塞,直到线程执行完。 - 分离的(detached)
thread.detach,创建线程与线程分离,不具有控制线程的权利,两个线程独立运行,最后线程资源会由系统自动释放。
锁(Lock)
有四类锁。
- 互斥锁
线程获取不到锁便阻塞。 - 自旋锁
线程循环获取锁,不会阻塞,适用于临界区执行时间短(能很快获取锁)的程序,有效避免了线程调度浪费的时间,但一直占用CPU。 - 条件变量
与锁的概念不同,而是等待某个条件满足,经常用于线程间同步,比如线程A的条件依赖与线程B的设置,那么在线程B设置后,会通知阻塞的线程A向下执行。 - 读写锁
假设现在读锁锁定了临界区,那么后来的读锁依然能够进入临界区,这样可以允许并行读取公共资源(读锁锁住的临界区只允许读操作),如果后来的是写锁,那么写锁阻塞,如果在这之后再来读锁,那么读锁也阻塞,这样做是为了防止读锁一直占用公共资源(写锁饥饿);
假设现在写锁锁定了临界区(写锁锁住的临界区允许写操作),后来的无论是读锁还是写锁,全部会阻塞。
线程池(ThreadPool)
在后台处理大量请求时,可能为每个请求创建一个线程,但是如果线程的创建和销毁比处理时间还长,那么对于频繁的创建线程是没有必要的,一般会用线程池去处理这样的请求。接下来会讲解如何用C++实现简单的线程池。线程池会固定线程数,利用生产者/消费者模型去处理任务。
任务接口
将任务抽象成接口,具体任务继承至该接口。class Task{protected: std::string name; void* data; //任务的一些属性public: Task(std::string, void*); virtual void run() = 0;//处理方法 virtual ~Task();};
生产者/消费者模型
生产者用来产生数据,消费者则处理数据,可以理解为队列,一端用来放任务,另一端用来处理任务。class ThreadPool{private: int thread_num; //固定线程数 static queue<Task*> task_queue;//任务队列,多个线程共享 static bool shutdown;//用于关闭线程池 static pthread_mutex_t mutex;//互斥锁 static pthread_cond_t condition; //条件变量 pthread_t* pthread_ids;//存储线程IDpublic: ThreadPool(int);//创建thread_num个线程 static void* threadFunc(void*);//关键,线程通过循环+阻塞+锁去从共享队列中去取任务执行 void addTask(Task*);//添加任务,由于访问共享队列,需要加锁 void joinAll();//所有任务执行完,回收所有线程 ~ThreadPool();};
线程处理任务(threadFunc)
(1)条件变量的使用需要用到互斥锁,因为判断的条件是共享队列的长度,对于共享资源的访问都需要加锁。
(2)在唤醒线程到重新加锁中间,共享数据可能发生变化,需要重新判断,所以引入循环判断。void* ThreadPool::threadFunc(void* threadData){ while (!shutdown) { pthread_mutex_lock(&mutex); while (task_queue.size() == 0 && !shutdown) { pthread_cond_wait(&condition, &mutex); //先释放锁,然后阻塞 //当收到通知,先唤醒线程,然后重新加锁 } if (task_queue.size() > 0) { Task* task = task_queue.front(); task_queue.pop(); pthread_mutex_unlock(&mutex); task->run(); } else pthread_mutex_unlock(&mutex); } return (void*)0;}
源码地址:https://github.com/wedy542700927/ThreadPool
这是一个简单的线程池实现,如果某个线程做了过多的任务,说明每个线程所分到的时间片不等。是否需要平衡时间片分配,以及如何做线程调度,定时器等也是需要考虑的问题。
阅读全文
0 0
- 线程池 线程锁
- 线程、锁、线程池
- 线程、线程池、并发、同步、异步、锁
- JAVA-线程/线程锁
- 线程及线程锁
- 线程与线程池
- 线程池 线程优先级
- Executor线程,线程池
- 线程、多线程、线程池
- IOS-线程、线程池
- Java线程:线程池
- 线程和线程池
- 线程、多线程、线程池
- 线程、多线程、线程池
- 线程(六)线程池
- ExecutorService(线程池)+线程
- 线程和线程池
- 线程&线程池 简略
- 利用Map.EntrySet遍历
- 什么是Scrum?
- Java 内存分配浅析
- 虚拟linux环境下h5py的安装与使用
- 解决systemback 无法生成超过4G的iso的问题
- 线程、锁、线程池
- python 递归下载ftp文件夹及文件
- SSM框架Jsp页面POST提交的中文数据保存到数据库变成乱码问题的分析
- 关于iOS沙盒的目录结构和获取
- 树莓派体验13
- 三年后的回看
- 单例模式
- 颜色格式转换:FFmpeg源代码简单分析:libswscale的sws_scale()
- javaweb学习总结——Filter(过滤器)学习