系统编程 day08 信号函数(信号量的使用方法,申请信号量初始化信号量 销毁信号的函数 (signal 信号捕捉函数)

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;

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redisson信号量可以用来阻塞线程。当信号量的许可数量为0时,尝试获取许可的线程会被阻塞,直到其他线程释放了许可。通过控制许可数量,可以限制同时访问某个资源的线程数量,以保证资源的合理使用。 具体来说,Redisson提供了tryAcquire()方法来尝试获取信号量的许可。当许可数量为0时,该方法会阻塞线程,直到有可用的许可为止。 通过使用Redisson信号量,可以实现线程之间的同步和资源的有序访问,确保线程的安全性和资源的合理利用。这在多线程编程中非常有用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [day109-缓存-分布式锁-Redisson-信号量测试](https://blog.csdn.net/JavaCoder_juejue/article/details/115057538)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [python线程信号量semaphore使用解析](https://download.csdn.net/download/weixin_38526979/12857460)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [redisson中Semaphore的信号量介绍及其原理](https://blog.csdn.net/qq_50652600/article/details/131576796)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值