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 <semaphore.h>
原型:int sem_init(sem_t *sem,int pshared,unsigned int value);
参数: sem:信号量 pshared:决定信号量能否在几个进程间共享。由于目前Linux还没有实现进程间共享信号量,所以这个值只能够取0 value:信号量初始化值
返回值:成功:0 出错:-1
4.sem_getvalue--得到信号量值
头文件:#include <semaphore.h>
原型:int sem_getvalue(sem_t *sem,int * val);
参数:sem为指向信号灯的指针,val是用于存储所查询到的信号量值
返回值:成功返回0,失败返回-1
5.sem_destroy--清理信号量
头文件:#include <semaphore.h>
原型: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 <semaphore.h>
函数原形:int sem_post(sem_t *sem);
参数:sem 指向信号灯的指针
返回值:若成功则返回0,否则返回-1。
功能补充:当一个线程使用完某个信号灯时,它应该调用sem_post来告诉系统申请的资源已经用完。本函数和sem_wait函数的功能正好相反,它把所指定的信号灯的值加1,然后唤醒正在等待该信号灯值变为正数的任意线程。
89..代码:
/************************************************************************************************************************************************************************************************************************
*文件名:
*作 者:She001
*时 间:
*版 本:
*作 用:
****************************************************************************************************************************************************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<semaphore.h> //信号量的使用的函数
// 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<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<semaphore.h> //信号量的使用的函数
// 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<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<signal.h>
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<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<signal.h>
//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<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<signal.h>
//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;
}