南宁网站开发软件,过年wordpress主机,河南城乡建设网站,机械网站建设方案处理信号好的三种方法#xff1a;默认动作#xff0c;忽略动作#xff0c;自定义处理#xff08;信号的捕捉#xff09;
自定义的方法如下所示#xff1a;
void hander()
{cout .... endl;
}int main(){// 对信号的自定义捕捉#xff0…处理信号好的三种方法默认动作忽略动作自定义处理信号的捕捉
自定义的方法如下所示
void hander()
{cout .... endl;
}int main(){// 对信号的自定义捕捉我们只要捕捉一次后续一直有效/signal(2, hander);//对2号信号自定义方法一直不产生2好信号就不会被捕捉// 2. 可以对更多的信号进行捕捉signal(3, hander);signal(4, hander);signal(5, hander);// 3. 2 号信号SIGINT默认是终止进程// 4. ctrlc --- 就是给目标进程发送2号信号因为SIGINT默认是终止进程// signal(3, hander);// signal(4, hander);// signal(5, hander);while(true){std::cout hello bit, pid: getpid() std::endl;sleep(1);}}
发送信号本质就是修改指定进程pcb是一种内核数据结构只有os才可以修改中的信号的指定位图。
信号产生
1.通过kill命令向指定进程发送信号kill -x pid根据某个x信号使某个进程执行该信号
2.键盘可以产生信号ctrlc2信号终止进程ctrl\3信号终止进程。
3.系统调用向指定进程发送指定信号。 // 0 1 2
//./mykill 2 1234给1234进程发送2号信号int main(int argc, char *argv[])
{if(argc ! 3){std::cerr Usage: argv[0] signum pid std::endl;return 1;}pid_t pid std::stoi(argv[2]);int signum std::stoi(argv[1]);kill(pid, signum);
}
Aborted(6号信号)信号就算自定义了最后还会终止。
9号信号不允许自定义捕捉。
4.软件条件 5.异常
程序异常向进程发送信号 终止进程的本质就是释放上下文的数据。 信号的保存
实际执⾏信号的处理动作称为信号递达信号的处理
信号从产⽣到递达之间的状态,称为信号未决(Pending)。已经产生了还没有处理信号
进程可以选择阻塞(Block)某个信号阻塞一个信号则对应的信号一旦产生一直不做处理
信号保存的过程如下 信号的处理
signal(2,handler);//自定义捕捉
signal(2,SIG_IGN);//忽略一个信号
signal(2,SIG_DFL);//默认处理动作
信号处理流程 cpu中有一个寄存器叫做ecx,里面可以存放如果是0就是内核态3就是用户态进而实现用户态和内核态之间的切换。
当前如果正在对信号x进行处理默认x信号会自动屏蔽当x信号处理完成时会自动解除对x信号的屏蔽。
线程
进程是资源分配的基本单位线程是调度的基本单位。
操作系统对内存管理的基本的单位是4kb。
线程:在进程内部运行是cpu调度的基本单位。
linux中的线程是虚拟存在的是进程模拟的windows下的线程是真实存在的。
cpu看到的执行流进程linux中的执行流是轻量级的进程
ps -aL查看进程pid和线程LWP当pidLWP时该线程为主线程。
创建进程的成本比较高线程成本比较低启动时。
线程调度的成本比较低运行时因为cpu中有一个寄存器cache运行时会提前将数据和代码刷新到cache中然后再cache中执行程序当进程调度时需要将cache进行清空并重新刷新线程调度不需要因为线程调度cache中的代码是共享的即 共享地址空间。所以成本低。面试
线程缺点
健壮性降低 在⼀个多线程程序⾥因时间分配上的细微偏差或者 因共享了不该共享的变量⽽造成不良影响的可能性是很⼤的换句话说线程之间是缺乏保护 的。
缺乏访问控制 进程是访问控制的基本粒度在⼀个线程中调⽤某些OS函数会对整个进程造成影响。
线程中私有的部分
一组寄存器重要栈重要线程ID信号屏蔽字调度优先级
单个线程如果出现除零野指针问题导致线程崩溃进程也会随着崩溃进程终⽌该进程内的所有线程也就随即退出。
进程中的多个线程共享同⼀地址空间,因此TextSegment、DataSegment都是共享的,如果定义⼀个函数,在各线程中都可以调 ⽤,如果定义⼀个全局变量,在各线程中都可以访问到。
线程创建的系统调用 实现代码如下
// 新线程
void* threadStart(void* args)
{while (true){sleep(1);std::cout new thread running... , pid: getpid() , gval: gval , gval: gval std::endl;}
}
int main()
{pthread_t tid1;pthread_create(tid1, nullptr, threadStart, (void*)thread-new);// 主线程while (true){std::cout main thread running... , pid: getpid() , gval: gval , gval: gval std::endl;}return 0;
}
线程等待新线程必须被主线程等待 int main()
{pthread_t tid; // unsigned long int// 问题1: main 和 new 线程谁先运行不确定//(void*)td参数可以传任意类型也可以是自定义类型int n pthread_create(tid, nullptr, threadRun, (void*)td);if(n ! 0) // 后面我们暂时就关心了{std::cerr create thread error std::endl;return 1;}// 问题2期望谁最后退出 main thread,如何保证呢n pthread_join(tid, nullptr); // join来保证。 不join会造成类似僵尸进程的问题if(n 0){std::cout main thread wait success, new thread exit code: result-print() std::endl;}return 0;
} 在上述代码中:线程的id是一个虚拟地址。
//新线程函数的返回只考虑正确的返回不考虑异常异常了整个进程就崩溃了包括主线程。
//也可以传递任意类型但你一定要能想得起来也可以传递类对象的地址
void *threadRun(void *args)
{int cnt 10;while(cnt){sleep(3); std::cout td-name run ... , cnt: cnt-- std::endlint *p nullptr;*p 100; // 故意野指针}delete td;return (void*)0;
}
多线程创建 int main()//线程的创建和等待
{// vectorpthread_t tids;// //6.创建多线程// for(int i0;inum;i)// {// //1.线程的id// pthread_t tid;// //2.线程的name// char *name new char[128];// snprintf(name,128,thread-%d,i1);// pthread_create(tid,nullptr,threadrun,/*线程的名字*/name);// //3.保存所有信息的id// tids.emplace_back(tid);// }// //创建多线程的等待// for(auto tid:tids)// {// void* name nullptr;// pthread_join(tid,name);// }
void* threadrun(void* args)//创建多线程需要的新线程函数
{//pthread_detach(pthread_self());//线程分离string name static_castconst char*(args);while (true){cout name is runing endl;sleep(1);}//exit(1)专门用来终止进程的不能用来终止线程//return args;//pthread_exit(args);//专门终止一个线程
}
const int num 10;
//main函数结束main thread结束表示进程也就结束
int main()//线程的创建和等待
{//7.新线程的终止方法//(1)函数return//2pthread_exit()专门一个终止线程//3int pthread_cancel(pthread_t thread)取消线程前提是线程要存在返回结果是-1vectorpthread_t tids;//6.创建多线程for(int i0;inum;i){//1.线程的idpthread_t tid;//2.线程的namechar *name new char[128];snprintf(name,128,thread-%d,i1);pthread_create(tid,nullptr,threadrun,/*线程的名字*/name);//3.保存所有信息的idtids.emplace_back(tid);}// //创建多线程的等待for(auto tid:tids){pthread_cancel(tid);//取消线程coutcancel threadvoid* result nullptr;pthread_join(tid,result);//线程被取消的后果是-1}return 0;
}
线程分离
void* threadrun(void* args)//创建多线程需要的新线程函数
{pthread_detach(pthread_self());//自己要线程分离string name static_castconst char*(args);while (true){cout name is runing endl;sleep(1);}//exit(1)专门用来终止进程的不能用来终止线程pthread_exit(args);//专门终止一个线程
}
const int num 10;
//main函数结束main thread结束表示进程也就结束
int main()//线程的创建和等待
{//8.可以不join线程让他执行完就退出//线程分离int pthread_detach(pthread_t thread)a. 一个线程被创建默认是joinable的必须要被join的.// b. 如果一个线程被分离线程的工作状态分离状态不须要/不能被join了. 依旧属于进程内部但是不需要被等待了vectorpthread_t tids;// //6.创建多线程for(int i0;inum;i){//1.线程的idpthread_t tid;//2.线程的namechar *name new char[128];snprintf(name,128,thread-%d,i1);pthread_create(tid,nullptr,threadrun,/*线程的名字*/name);//3.保存所有信息的idtids.emplace_back(tid);}//主线程主动分离// for(auto tid:tids)// {// pthread_detach(tid);//主线程分离新线程新线程必须存在// }return 0;
}
给用户提供的线程id,不是内核中的lwp,而是pthread库里面维护的唯一值。
id就是在内存中的一个起始地址。 多个线程能够看到的资源---共享资源。
线程封装
#include iostream
#include string
#include pthread.h
#includefunctional
using namespace std;namespace ThreadModule {typedef void (*func_t)(const std::string name); // 函数指针类型:返回值是void class Thread{public:void Excute(){std::cout _name is running std::endl;_isrunning true;_func(_name);_isrunning false;}public:Thread(const std::string name, func_t func) :_name(name), _func(func){std::cout create name done std::endl;}static void* ThreadRoutine(void* args)//这是类里面的默认有this和创建的主线程参数不匹配所以要加static;新线程都会执行该方法{Thread* self static_castThread*(args);//获得了当前对象self-Excute();//调用回调函数return nullptr;}bool Start(){int n ::pthread_create(_tid, nullptr, ThreadRoutine, nullptr);//使用的是pthread库里面的if (n ! 0){return false;}return true;}std::string Status()//线程启动了检测状态{if (_isrunning) return running;else return sleep;}std::string Name(){return _name;}void Stop(){if (!_isrunning){pthread_cancel(_tid);_isrunning false;}}void Join(){pthread_join(_tid, nullptr);}~Thread(){ }private:string _name;pthread_t _tid;bool _isrunning;func_t _func;//线程要执行的回调函数};
}
线程互斥
互斥锁任何时刻只允许一个线程进行资源访问。
对临界资源进行保护本质就是对临界区的代码进行保护。
对所有资源进行保护本质是通过代码访问的保护资源本质就是把访问资源的代码保护起来。
原子性要么不做要做就做完没有中间状态只有一条汇编语言。
线程申请锁成功了继续向后运行申请所失败则被阻塞。
当线程申请所成功了执行临界区代码期间被切换了其他线程不能进入因为没有释放锁。 线程同步
同步在保证数据安全的前提下让线程能够按照某种特定的顺序访问临界资源从⽽有效避免 饥饿问题。
条件变量 条件变量接口代码的实现
//条件变量就是来唤醒线程的
#include iostream
#include string
#include unistd.h
#include pthread.hconst int num 5;
pthread_mutex_t gmutex PTHREAD_MUTEX_INITIALIZER;//定义一个互斥锁
pthread_cond_t gcond PTHREAD_COND_INITIALIZER;//定义一个条件变量void *Wait(void *args)
{std::string name static_castconst char *(args);while (true){pthread_mutex_lock(gmutex);pthread_cond_wait(gcond, gmutex /*?*/); // 这里就是线程等待的位置usleep(10000);std::cout I am : name std::endl;pthread_mutex_unlock(gmutex);}
}int main()
{pthread_t threads[num];for (int i 0; i num; i){char *name new char[1024];snprintf(name, 1024, thread-%d, i 1);pthread_create(threads i, nullptr, Wait, (void *)name);//创建线程usleep(10000);}// 唤醒其他线程while (true){// pthread_cond_signal(gcond);//唤醒一个线程pthread_cond_broadcast(gcond);//唤醒所有线程std::cout 唤醒一个线程.... std::endl;sleep(2);}for (int i 0; i num; i)//线程等待{pthread_join(threads[i], nullptr);}return 0;
} 生产消费模型 阻塞队列 阻塞队列(BlockingQueue)是⼀种常⽤于实现⽣产者和消费者模型的数据结构。其与 普通的队列区别在于当队列为空时从队列获取元素的操作将会被阻塞直到队列中被放⼊了元 素当队列满时往队列⾥存放元素的操作也会被阻塞直到有元素被从队列中取出。
321原则1一个交易场所特定数据结构形式存在的一段内存空间22中角色生产角色消费角色即生产线程消费线程3三种关系即生产和生产互斥关系消费和消费互斥关系生产和消费(互斥同步关系)之间的关系。
生产消费模型的模拟实现
“BlockQueue.hpp”#include iostream
#include string
#include queue
#include pthread.hconst static int defaultcap 5;template typename T
class BlockQueue
{
private:bool IsFull(){return _block_queue.size() _max_cap;}bool IsEmpty(){return _block_queue.empty();}public:BlockQueue(int cap defaultcap) : _max_cap(cap){pthread_mutex_init(_mutex, nullptr);//锁的初始化pthread_cond_init(_p_cond, nullptr);//条件变量初始化pthread_cond_init(_c_cond, nullptr);}void Pop(T* out){pthread_mutex_lock(_mutex);// 当一个生产者两个消费者时while (IsEmpty()) // while可以保证代码的鲁棒性(健壮性){// 添加尚未满足但是线程被异常唤醒的情况叫做伪唤醒pthread_cond_wait(_c_cond, _mutex); //一个消费者竞争成功会拿走数据另一个消费者在锁这里等待当被释放时向下运行没有数据了绕过了判断队列为空的条件所以用while不用if}// 1. 没有空 || 2. 被唤醒了*out _block_queue.front();_block_queue.pop();// if(_block_queue.size() hight_water)// pthread_cond_signal(_p_cond);pthread_mutex_unlock(_mutex);pthread_cond_signal(_p_cond);}// 一个生产者void Equeue(const T in){pthread_mutex_lock(_mutex);while (IsFull()) {// 满了生产者不能生产必须等// 被调用的时候除了让自己继续排队等待还会自己释放传入的锁// 函数返回的时候不就还在临界区了// 返回时必须先参与锁的竞争重新加上锁该函数才会返回pthread_cond_wait(_p_cond, _mutex);}// 1. 没有满 || 2. 被唤醒了_block_queue.push(in); // 生产到阻塞队列pthread_mutex_unlock(_mutex);// 让消费者消费pthread_cond_signal(_c_cond); // 唤醒}~BlockQueue(){pthread_mutex_destroy(_mutex);pthread_cond_destroy(_p_cond);pthread_cond_destroy(_c_cond);}private:std::queueT _block_queue; // 临界资源 定义一个队列int _max_cap;//队列的容量pthread_mutex_t _mutex;//定义一个锁pthread_cond_t _p_cond; // 生产者条件变量pthread_cond_t _c_cond; // 消费者条件变量
};
#includeiostream
#includefunctional// typedef std::functionvoid() task_t;
using task_t std::functionvoid();//定义一个函数类型返回值是void,参数为空void Download()
{std::cout 我是一个下载的任务 std::endl;
}void* Consumer(void* args)
{BlockQueuetask_t* bq static_castBlockQueuetask_t *(args);while (true){// 1. 获取数据task_t t;bq-Pop(t);// 2. 处理数据// t.Excute();t();// std::cout Consumer - t.result() std::endl;}
}void* Productor(void* args)
{srand(time(nullptr) ^ getpid());BlockQueuetask_t* bq static_castBlockQueuetask_t *(args);while (true){bq-Equeue(Download);std::cout Productor - Download std::endl;sleep(1);}
}int main()
{BlockQueuetask_t* bq new BlockQueuetask_t();pthread_t c p;pthread_create(c, nullptr, Consumer, bq);pthread_create(p, nullptr, Productor, bq);pthread_join(c, nullptr);pthread_join(p, nullptr);return 0;
}
信号量
信号量系统调用 环形队列--生产消费模型
RingQueue.hpp#include iostream
#include vector
#include string
#include pthread.h
#include semaphore.htemplate typename T
class RingQueue
{
private:void P(sem_t s)//p操作{sem_wait(s);}void V(sem_t s)//v操作{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;
};
#include RingQueue.hpp
#include Task.hpp
#include iostream
#include pthread.h
#include unistd.h
#include ctimevoid* Consumer(void* args)
{RingQueueTask* rq static_castRingQueueTask *(args);//Task是一个类while (true){Task t;// 1. 消费rq-Pop(t);// 2. 处理数据t();//Task有一个重载函数
}
void* Productor(void* args)
{RingQueueTask* rq static_castRingQueueTask *(args);while (true){sleep(1);// 1. 构造数据int x rand() % 10 1; //[1, 10]usleep(x * 1000);int y rand() % 10 1;Task t(x, y);// 2. 生产rq-Push(t);}
}int main()
{srand(time(nullptr) ^ getpid());RingQueueTask* rq new RingQueueTask(5);pthread_t c1, p1;pthread_create(c1, nullptr, Consumer, rq);pthread_create(p1, nullptr, Productor, rq);pthread_join(c1, nullptr)pthread_join(p1, nullptr);return 0;
}