企业建网站的目的,白山市网站建设,东莞专业做淘宝网站推广,上海注册外贸公司1.信号量
POSIX信号量#xff0c;用与同步操作#xff0c;达到无冲突的访问共享资源目的#xff0c;POSIX信号量可以用于线程间同步
初始化信号量
#include semaphore.h
int sem_init(sem_t *sem, int pshared, unsigned int value); sem#xff1a;指向sem_t类…1.信号量
POSIX信号量用与同步操作达到无冲突的访问共享资源目的POSIX信号量可以用于线程间同步
初始化信号量
#include semaphore.h
int sem_init(sem_t *sem, int pshared, unsigned int value); sem指向sem_t类型信号量结构的指针该结构将被初始化pshared指示信号量是否被多个进程共享如果pshared为0则信号量只被统一进程的线程共享如果 pshared不为0则信号量可以被多个进程共享value信号量的初始值
成功时返回 0失败时返回 -1并设置 errno 以指示错误类型。
销毁信号量
int sem_destroy(sem_t *sem)
等待信号量
int sem_wait(sem_t *sem); //P()
等待信号量会将信号量的值-1
发布信号量
int sem_post(sem_t *sem);//V()
发布信号量表示资源使用完毕可以归还资源了将信号量值1 2.基于信号量的环形队列 在环形队列中
队列为空让生产者先访问队列为满让消费者先访问队列不为空队列不为满生产和消费同时进行
关于消费者消费的是数据资源生产的是空间资源
关于生产者生产的是数据资源消费的是空间资源 #pragma once #includeiostream
#includevector
#includestring
#includepthread.h
#includesemaphore.htemplateclass T
class RingQueue
{
private:void P(sem_t s){sem_wait(s);}void V(sem_t s){sem_post(s);}
public:RingQueue(int max_cap):_ringqueue(max_cap),_max_cap(max_cap),_c_step(0),_p_step(0){sem_init(_data_sem,0,0);sem_init(_space_sem,0,_max_cap);pthread_mutex_init(_c_mutex,nullptr);pthread_mutex_init(_p_mutex,nullptr);}void Push(const T in)//生产者{// 信号量是一个计数器是资源的预订机制。//预订在外部可以不判断资源是否满足就可以知道内部资源的情况P(_space_sem);pthread_mutex_lock(_p_mutex);_ringqueue[_p_step]in;_p_step;_p_step%_max_cap;pthread_mutex_unlock(_p_mutex);V(_data_sem);}void Pop(T* out)//消费者{P(_data_sem);pthread_mutex_lock(_c_mutex);*out_ringqueue[_c_step];_c_step;_c_step%_max_cap;pthread_mutex_unlock(_c_mutex);V(_space_sem);}~RingQueue(){sem_destroy(_data_sem);sem_destroy(_space_sem);pthread_mutex_destroy(_c_mutex);pthread_mutex_destroy(_p_mutex);}
private:std::vectorT _ringqueue;int _max_cap;int _c_step;int _p_step;sem_t _data_sem;sem_t _space_sem;pthread_mutex_t _c_mutex;pthread_mutex_t _p_mutex;};#pragma once#includeiostream
#includefunctional// typedef std::functionvoid() task_t;
// using task_t std::functionvoid();// void Download()
// {
// std::cout 我是一个下载的任务 std::endl;
// }// 要做加法
class Task
{
public:Task(){}Task(int x, int y) : _x(x), _y(y){}void Excute(){_result _x _y;}void operator ()(){Excute();}std::string debug(){std::string msg std::to_string(_x) std::to_string(_y) ?;return msg;}std::string result(){std::string msg std::to_string(_x) std::to_string(_y) std::to_string(_result);return msg;}private:int _x;int _y;int _result;
};#include RingQueue.hpp
#include Task.hpp
#include iostream
#include pthread.h
#include unistd.h
#include ctimevoid* Consumer(void* args)
{RingQueueTask* rqstatic_castRingQueueTask*(args);while(true){Task t;rq-Pop(t);t();std::coutConsumer- t.result()std::endl;}
}void* Productor(void* args)
{RingQueueTask* rqstatic_castRingQueueTask*(args);while(true){sleep(1);int xrand()%101;usleep(x*1000);int yrand()%101;Task t(x,y);rq-Push(t);std::coutProductor- t.debug()std::endl;}}
int main()
{srand(time(nullptr)^getpid());RingQueueTask*rqnew RingQueueTask(5);pthread_t c1, c2, p1, p2, p3;pthread_create(c1, nullptr, Consumer, rq);pthread_create(c2, nullptr, Consumer, rq);pthread_create(p1, nullptr, Productor, rq);pthread_create(p2, nullptr, Productor, rq);pthread_create(p3, nullptr, Productor, rq);pthread_join(c1, nullptr);pthread_join(c2, nullptr);pthread_join(p1, nullptr);pthread_join(p2, nullptr);pthread_join(p3, nullptr);return 0;
} 3.线程池 线程池的概念
线程池是一种线程使用模式。线程过多会带来调度开销进而影响缓存局部性和整体性能。而线程池维护着多个线程等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。
线程池的应用场景
1. 需要大量的线程来完成任务且完成任务的时间比较短。 WEB服务器完成网页请求这样的任务使用线程池技
术是非常合适的。因为单个任务小而任务数量巨大你可以想象一个热门网站的点击次数。 但对于长时间的任务比如一个Telnet连接请求线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。
2. 对性能要求苛刻的应用比如要求服务器迅速响应客户请求。
3. 接受突发性的大量请求但不至于使服务器因此产生大量线程的应用。突发性大量客户请求在没有线程池情
况下将产生大量线程虽然理论上大部分操作系统线程数目最大值不是问题短时间内产生大量线程可能使内存到达极限出现错误.
线程池示例
1. 创建固定数量线程池循环从任务队列中获取任务对象
2. 获取到任务对象后执行任务对象中的任务接口 线程池代码示例 4.可重入VS线程安全
概念
线程安全多个线程并发执行同一段代码时不会出现不同的结果常见对全局变量或者静态变量进行操作并且没有锁的保护下会出现该问题重入同一个函数被不同执行流调用时当前一个线程还没有执行完就有其他执行流再次进入我们称之为重入。一个函数在重入情况下运行结果不会出现问题则该函数称为可重入函数否则就不是可重入函数
可重入和线程安全联系
函数是可重入的那线程就是安全的函数是不可重入的那就不能由多个线程使用有可能引发线程安全问题如果一个函数中有全局变量那么这个函数既不是线程安全也不是可重入的
可重入和线程安全的区别
可重入函数是线程安全函数的一种线程安全不一定是可重入而可重入函数则一定是线程安全的如果对临界资源的访问加上锁则这个函数是线程安全的
5.死锁
死锁的概念
死锁是指在一组进程中的各个进程均占有不会释放的资源但因互相申请被其他进程所占有的不会释放的资源而处于永久等待的一种状态
死锁的四个必要条件
互斥条件一个资源每次只能被一个执行流使用请求与保持条件一个执行流因请求资源而阻塞时对已获得的资源保持不放不剥夺条件一个执行流已获得的资源在末使用完之前不能强行剥夺循环等待条件若干执行流之间形成一种头尾相接的循环等待资源的关系
避免死锁
破坏死锁的四个必要条件加锁顺序一致避免锁未释放的场景资源一次性分配