1.线程同步-信号量
信号量从本质上是一个非负整数计数器,通常被用来控制对公共资源的访问。
当可用的公共资源增加时,调用函数sem_post()增加信号量。 只有当信号量值大于0时,函数sem_wait()才能返回,并将信号量的值减1,当信号量等于0时,sem_wait()将被阻塞直到信号量的值大于0。 函数sem_trywait()是函数sem_wait()的非阻塞版本。
2.信号量也就是操作系统中所用到的PV 原语,它广泛用于进程或线程间的同步与互斥。
信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。
PV原语的工作原理:PV原语是对整数计数器信号量sem的操作。一次P操作使sem减一,而一次V操作使sem 加一。进程(或线程)根据信号量的值来判断是否对公共资源具有访问权限。当信号量sem 的值大于等于零时,该进程(或线程)具有公共资源的访问权限;相反,当信号量sem的值小于零时,该进程(或线程)就将阻塞直到信号量sem的值大于等于0 为止。
3.sem_init用于创建无名信号量并初始化它的值
头文件:#include
原型:int sem_init(sem_t *sem,int pshared,unsigned int value);
参数: sem:信号量 pshared:决定信号量能否在几个进程间共享。由于目前Linux还没有实现进程间共享信号量,所以这个值只能够取0 value:信号量初始化值
返回值:成功:0 出错:-1
4.sem_getvalue--得到信号量值
头文件:#include
原型:int sem_getvalue(sem_t *sem,int * val);
参数:sem为指向信号灯的指针,val是用于存储所查询到的信号量值
返回值:成功返回0,失败返回-1
5.sem_destroy--清理信号量
头文件:#include
原型:int sem_destroy (sem_t * sem);
参数:sem为指向信号量的指针
返回值:成功返回0,失败返回-1
6.sem_wait-等待共享资源 ( -1 函数)
sem_trywait--等待共享资源
参数:sem 指向信号灯的指针 返回值:若成功则返回0,否则返回-1。
功能补充:可以用sem_wait来申请共享资源,sem_wait函数可以测试所指定信号灯的值,如果该值大于0,那就将它减1并立即返回。我们就可以使用申请来的共享资源了。如果该值等于0,调用线程就被进入睡眠状态,直到该值变为大于0,这时再将它减1,函数随后返回。sem_wait操作必须是原子的。
sem_wait与sem_trywait的区别: sem_wait和sem_trywait相当于P操作,它们都能将信号量的值减一,两者的区别在于若信号量小于零时,
sem_wait将会阻塞进程,
而sem_trywait则会立即返回
int sem_post(sem_t *sem); ( +1函数 )
7.头文件:#include
函数原形:int sem_post(sem_t *sem);
参数:sem 指向信号灯的指针
返回值:若成功则返回0,否则返回-1。
功能补充:当一个线程使用完某个信号灯时,它应该调用sem_post来告诉系统申请的资源已经用完。本函数和sem_wait函数的功能正好相反,它把所指定的信号灯的值加1,然后唤醒正在等待该信号灯值变为正数的任意线程。
89..代码:
- /************************************************************************************************************************************************************************************************************************
- *文件名:
- *作 者:She001
- *时 间:
- *版 本:
- *作 用:
- ****************************************************************************************************************************************************************************************************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
//信号量的使用的函数 - // 0.信号量的使用方法
- //1.申请信号量
- //2.初始化信号量
- //3.p 操作 -1操作
- //4.读写操作
- //5.v操作 +1操作
- //6.销毁信号量
- //
- int main(int argc,char *argv[])
- {
-
-
- //1.申请信号量
- sem_t sem;
- //2.初始化信号量
- if(sem_init(&sem,0,1)<0) //灯亮
- {
- perror("sem_init error\n");
- return -1;
- }
- else
- {
- printf("sem_init ok\n");
- }
- //查看信号量
- int value =0;
- sem_getvalue(&sem,&value);
- printf("1 value = %d\n",value);
-
-
- //3.p 操作 -1操作
- sem_wait(&sem); //关灯操作 (堵塞版)
- sem_getvalue(&sem,&value);
- printf("2 value = %d\n",value);
-
- int s=sem_post(&sem); //开灯操作
- if(s<0)
- {
- perror("sem_post error\n");
- }
- else
- {
- printf("sem_post ok\n");
- }
-
- while(sem_trywait(&sem)) //不堵塞版开灯操作
- {
- perror("sem_trywait error\n");
- sleep(1);
- }
-
- //4.读写操作
- printf("do something to resourme\n");
- //5.v操作 +1操作
- s=sem_post(&sem); //开灯操作
- if(s<0)
- {
- perror("sem_post error\n");
- }
- else
- {
- printf("sem_post ok\n");
- }
- sem_getvalue(&sem,&value);
- printf("3 value = %d\n",value);
- //6.销毁信号量
- sem_destroy(&sem);
- return 0;
-
- }
9.程序功能: 把信号量的方法用到 线程之中
代码:
- /************************************************************************************************************************************************************************************************************************
- *文件名:
- *作 者:She001
- *时 间:
- *版 本:
- *作 用:
- ****************************************************************************************************************************************************************************************************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
//信号量的使用的函数 - // 0.信号量的使用方法
- //1.申请信号量
- //2.初始化信号量
- //3.p 操作 -1操作
- //4.读写操作
- //5.v操作 +1操作
- //6.销毁信号量
- //
-
-
-
- int num=100;
- //1.申请信号量 (全局变量)
- sem_t sem;
- void * pthread_fun1(void *arg)//创建线程的函数
- {
- while(sem_trywait(&sem)) //不堵塞版关灯操作
- {
- perror("fun1 sem_trywait error\n");
- sleep(1);
- }
-
- printf("this is %s %d %ld start \n",__func__,getpid(),pthread_self());
- for(int i=0;i<5;i++)
- {
- num+=1;
- printf("1111111 :%d\n",num);
- sleep(1);
- }
- printf("this is %s %d %ld end \n",__func__,getpid(),pthread_self());
- int s=sem_post(&sem); //开灯操作
- if(s<0)
- {
- perror("sem_post error\n");
- }
- else
- {
- printf("sem_post ok\n");
- }
-
- }
-
- void * pthread_fun2(void *arg)//创建线程的函数
- {
- while(sem_trywait(&sem)) //不堵塞版关灯操作
- {
- perror("fun2 sem_trywait error\n");
- sleep(1);
- }
- printf("this is %s %d %ld start \n",__func__,getpid(),pthread_self());
- for(int i=0;i<5;i++)
- {
- num-=2;
- printf("22222222 :%d \n",num);
- sleep(1);
- }
-
- printf("this is %s %d %ld end \n",__func__,getpid(),pthread_self());
- int s=sem_post(&sem); //开灯操作
- if(s<0)
- {
- perror("sem_post error\n");
- }
- else
- {
- printf("sem_post ok\n");
- }
- }
-
- void * pthread_fun3(void *arg)//创建线程的函数
- {
- while(sem_trywait(&sem)) //不堵塞版关灯操作
- {
- perror("fun3 sem_trywait error\n");
- sleep(1);
- }
- printf("this is %s %d %ld start \n",__func__,getpid(),pthread_self());
- for(int i=0;i<5;i++)
- {
- num+=3;
- printf("333333333 :%d\n",num);
- sleep(1);
- }
- printf("this is %s %d %ld end \n",__func__,getpid(),pthread_self());
- int s=sem_post(&sem); //开灯操作
- if(s<0)
- {
- perror("sem_post error\n");
- }
- else
- {
- printf("sem_post ok\n");
- }
- }
-
-
- int main(int argc,char *argv[])
- {
-
-
- //2.初始化信号量
- if(sem_init(&sem,0,1)<0) //灯亮
- {
- perror("sem_init error\n");
- return -1;
- }
- else
- {
- printf("sem_init ok\n");
- }
- //查看信号量
-
-
-
-
-
- //创建线程
- int value =0;
- sem_getvalue(&sem,&value);
- printf("1 value = %d\n",value);
- pthread_t tid1 =0;
- pthread_t tid2 =0;
- pthread_t tid3 =0;
- pthread_create(&tid1,NULL,pthread_fun1,NULL);
- pthread_create(&tid2,NULL,pthread_fun2,NULL);
- pthread_create(&tid3,NULL,pthread_fun3,NULL);
-
-
- pthread_join(tid1,NULL); //不接受子线程的退出状态
- pthread_join(tid2,NULL); //不接受子线程的退出状态
- pthread_join(tid3,NULL); //不接受子线程的退出状态
-
- //6.销毁信号量
- sem_destroy(&sem);
- return 0;
-
- }
10.信号的介绍:
1.信号定义:信号(signal):是进程之间相互传递消息的一种方法,信号全称为软中断信号,也称作软中断。信号用来通知进程发生了异步事件。 信号事件的发生有两个来源: 1硬件来源,比如我们按下了键盘或者其它硬件故障; 2软件来源,最常用信号相关系统函数是kill(), raise(), alarm()和setitimer()等函数,软件来源还包括一些非法运算等操作。 注意:信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。
2进程对信号的处理
进程可以通过三种方式来响应和处理一个信号: 1忽略信号:忽略某个信号,对该信号不做任何处理,就象未发生过一样。 2捕捉信号:是类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处理.//编程。 3执行缺省操作:对该信号的处理保留系统的默认值,这种缺省操作,对大部分的信号的缺省操作是使得进程终止
3Linux支持的信号列表
11.信号发送与捕捉
kill()和raise() kill函数同读者熟知的kill系统命令一样,可以发送信号给进程或进程组
alarm()和pause()
kill –l 命令查看系统支持的信号列表
raise函数允许进程向自己发送信号
alarm()也称为闹钟函数,它可以在进程中设置一个定时器。当定时器指定的时间到时,内核就向进程发送SIGALRM信号。
pause()函数是用于将调用进程挂起直到收到信号为止。
kill 函数:
代码:
- /************************************************************************************************************************************************************************************************************************
- *文件名:
- *作 者:She001
- *时 间:
- *版 本:
- *作 用:kill 函数的测试
- ****************************************************************************************************************************************************************************************************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- int main(int argc,char *argv[])
- {
- printf("%s start \n",__func__);
- //kill(getpid(),SIGKILL);
- //kill(getppid(),SIGKILL); //ctrl + d 关闭终端
- kill(getpid(),SIGTSTP);
- printf("%s end\n",__func__);
-
-
- return 0;
-
- }
raise 函数
alarm 函数
代码:
- /************************************************************************************************************************************************************************************************************************
- *文件名:
- *作 者:She001
- *时 间:
- *版 本:
- *作 用:信号的其他函数
- ****************************************************************************************************************************************************************************************************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- //1.raise 只能给自己发信号
- //2.alarm 调用以后,内核在定的时间,到了之后,给本进程发送闹钟信号 (闹钟信号 的操作是终止本任务)
- //3.abort 终止 //核心已转储的函数
- //4.pause 让调用本函数的任务 停止 知道内核给本任务发送信号
-
- int main(int argc,char *argv[])
- {
- printf("%s start\n",__func__);
- //raise(SIGKILL);//杀死
- //raise(SIGTSTP);//暂停
- //raise(SIGINT);//终止
-
- alarm(5); //以秒为单位
- for(int i=1;i<=10;i++)
- {
- printf("this is alarm sig!\n");
- sleep(1);
- if(i==2)
- {
- //abort();
- pause();
- }
-
- }
-
-
- printf("%s end\n",__FILE__);//文件名字
-
-
-
- return 0;
-
- }
12.信号的处理
特定的信号是与相应的事件相联系的 一个进程可以设定对信号的相应方式
信号处理的主要方法有两种 使用简单的signal()函数
signal() 使用signal函数处理时,需指定要处理的信号和处理函数 使用简单、易于理解
代码:
- /************************************************************************************************************************************************************************************************************************
- *文件名:
- *作 者:She001
- *时 间:
- *版 本:
- *作 用:signal 函数的使用
- ****************************************************************************************************************************************************************************************************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- //1.signal
- //2.A 任务 给 B任务 发送信号 B任务有三种回应 1.忽略 2.捕获 3.缺省
- //
- //
-
- void sigfun(int signo)
- {
- if(signo ==SIGINT )
- {
- printf("file is ctrl + c\n");
- }
- else if(signo == SIGQUIT)
- {
- printf("file is ctrl + \\ \n");
- }
- else if(signo ==SIGTSTP)
- {
- printf("file is ctrl + z \n");
- }
- else if(signo=SIGALRM)
- {
- printf("alarm signal is buhuo1\n");
- }
- }
-
-
- int main(int argc,char *argv[])
- {
- printf("this is signal test start\n");
- signal(SIGINT,sigfun);
- signal(SIGQUIT,sigfun);
- signal(SIGTSTP,sigfun);
- signal(SIGALRM,sigfun);
- int num =20;
- alarm(5);
- //还原信号原来的功能 signal(SIGINT, SIG_DFL)
- //忽略信号的功能 singal(SIGINT, SIG_IGN);
-
- //可以捕获 alarm 函数的终止信号;
- while(num--)
- {
- printf("test num =%d\n",num);
- sleep(1);
- }
- printf("this is singal end \n");
-
- return 0;
-
- }