进程间通信——信号

1,什么是信号

信号是软件中断;信号提供了一种处理异步事件的方法:终端用户键入中断键,则会通过信号机构停止一个程序;是一种异步通信方式。

2,信号类型

Linux下查看支持的信号列表,可以直接输入kill -l;
在这里插入图片描述
简要说明;
名称 说明
SIGHUP 终止进程 终端线路挂断
SIGINT   终止进程 中断进程
SIGQUIT   建立CORE文件   终止进程,并且生成core文件
SIGILL   建立CORE文件 非法指令
SIGTRAP   建立CORE文件 跟踪自陷
SIGBUS   建立CORE文件 总线错误
SIGSEGV   建立CORE文件 段非法错误
SIGFPE   建立CORE文件 浮点异常
SIGIOT   建立CORE文件 执行I/O自陷
SIGKILL   终止进程 杀死进程
SIGPIPE   终止进程 向一个没有读进程的管道写数据
SIGALARM   终止进程 计时器到时
SIGTERM   终止进程 软件终止信号
SIGSTOP   停止进程 非终端来的停止信号
SIGTSTP   停止进程 终端来的停止信号
SIGCONT   忽略信号 继续执行一个停止的进程
SIGURG   忽略信号 I/O紧急信号
SIGIO   忽略信号 描述符上可以进行I/O
SIGCHLD   忽略信号 当子进程停止或退出时通知父进程
SIGTTOU   停止进程 后台进程写终端
SIGTTIN   停止进程 后台进程读终端
SIGXGPU   终止进程 CPU时限超时
SIGXFSZ   终止进程 文件长度过长
SIGWINCH   忽略信号 窗口大小发生变化
SIGPROF   终止进程 统计分布图用计时器到时
SIGUSR1   终止进程 用户定义信号1
SIGUSR2   终止进程 用户定义信号2
SIGVTALRM  终止进程 虚拟计时器到时

信号的处理方式有3种

1 忽略(就是不管你发啥我都不理你)
2默认处理方式(会终止一个进程)
3自定义处理方式(通过信号执行自定义函数)

3,signal函数

3,1函数介绍

#include <signal.h>
void (*signal (int signo , void (*func)(int))) (int);

返回:成功则为以前的信号处理配置,若出错则为 SIG_ERR

signal函数的原型说明此函数要求两个参数,返回一个函数指针,而该指针所指向的函数 无返回值(void)。
第一个参数signo是一个整型数,
第二个参数是函数指针,它所指向的函数需 要一个整型参数,无返回值。用一般语言来描述也就是要向信号处理程序传送一个整型参数, 而它却无返回值。当调用signal设置信号处理程序时,第二个参数是指向该函数 (也就是信号处 理程序)的指针。signal的返回值则是指向以前的信号处理程序的指针。

3,2例子

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
int			child_run = 0;
int			parent_run = 0;

void sig_child(int signum)    //子进程信号处理函数
{
	if(SIGUSR1 == signum)
	{
		printf("i am child sig\n");
                child_run = 1;
	}
}

void sig_parent(int signum)     //父进程的信号处理函数
{
	if(SIGUSR2 == signum)
	{
               printf("i am parent sig\n");
               parent_run = 1;
	}
}


int main(int argc, char **argv)
{
	pid_t				pid = -1;
        int			        child_statu;

	//注册信号
        signal(SIGUSR1,sig_child);
	signal(SIGUSR2,sig_parent);

	//创建进程
        pid = fork();
	if(pid < 0)
	{
		printf("creat fork failure\n");
		exit(0);
	}
       
        //子进程
        if(pid == 0)
	{
                printf("creat child fork successful,wait signal..\n");

                while(!child_run)     //阻塞等待父进程发信号
                {
                      sleep(1);

                }
                kill(getppid(),SIGUSR2);//子进程给父进程发运行信号
                
                return 0;
	}
      	else
	{
               
                printf("wait child_fork give signal...\n");
                 
		kill(pid,SIGUSR1);      //给子进程发信号

                while(!parent_run )       //阻塞等待子进程发信号
                {
                      sleep(1);
                }

                printf("parent_fork start\n");
                
               
                waitpid(&child_statu);//父进程等待子进程退出,避免僵死进程
	}

	return 0;
}

运行结果:
在这里插入图片描述

4,代码分析

4.1kill函数原型

在上面的代码中使用到了该函数来进行发送信号(此程序实际上是使用 kill 函数来发送信号。也常用此命令终止一个失控的后台进程。)

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);

pid:进程ID (process id)
sig:要发送的信号

4.2pid参数分析

pid: 取值有 4 种情况:

pid > 0: 将信号传送给进程 ID 为pid的进程。

pid = 0: 将信号传送给当前进程所在进程组中的所有进程。

pid = -1: 将信号传送给系统内所有的进程。

pid < -1: 将信号传给指定进程组的所有进程。这个进程组号等于 pid 的绝对值。

signum: 信号的编号,这里可以填数字编号,也可以填信号的宏定义,可以通过命令kill -l (“l” 为字母)进行相应查看。

返回值 : 成功返回 0; 错误返回 1

5,其他

5,1 查看进程

ps:查看进程状态 (一个瞬间的进程状态,静态)
top:“实时查看” ,按q退出 (实时动态显示)
pstree 树状查看 (可以看出所属子进程)

5.2、对某个进程发送信号

kill -s 指定发送一个信号 进程的pid
killall:指定一个应用程序名字去发送信号
kill -l 查看系统有什么信号
终端上按“Ctrl+c”组合键通常产生中断信号 SIGINT,终端上按“Ctrl+\”键通常产生中断信号 SIGQUIT,终端上按“Ctrl+z”键通常产生中断信号 SIGSTOP 等。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
信号量是一种用于进程通信和同步的机制。它是一个计数器,用于保证在共享资源上的互斥访问。在Linux系统中,可以使用信号量来实现进程的同步和互斥。以下是信号量的基本概念: - 计数器:信号量的值是一个计数器,它可以被多个进程共享。 - P操作:当一个进程需要访问共享资源时,它必须执行P操作,该操作会将信号量的值减1。如果信号量的值为0,则进程将被阻塞,直到信号量的值大于0。 - V操作:当一个进程使用完共享资源后,它必须执行V操作,该操作会将信号量的值加1。如果有进程正在等待该信号量,则唤醒其中一个进程继续执行。 在ZUCC中,可以使用信号量来实现进程的同步和互斥。首先,需要使用semget函数创建一个信号量集合,并使用semctl函数对信号量进行初始化。然后,可以使用semop函数执行P和V操作。例如,下面是一个简单的示例程序,用于演示信号量的使用: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/sem.h> #define SEM_KEY 1234 union semun { int val; struct semid_ds *buf; unsigned short *array; }; int main() { int semid, pid; union semun arg; struct sembuf sb; // 创建信号量集合 semid = semget(SEM_KEY, 1, IPC_CREAT | 0666); if (semid == -1) { perror("semget"); exit(EXIT_FAILURE); } // 初始化信号量 arg.val = 1; if (semctl(semid, 0, SETVAL, arg) == -1) { perror("semctl"); exit(EXIT_FAILURE); } // 创建子进程 pid = fork(); if (pid == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid == 0) { // 子进程执行P操作 sb.sem_num = 0; sb.sem_op = -1; sb.sem_flg = SEM_UNDO; if (semop(semid, &sb, 1) == -1) { perror("semop P"); exit(EXIT_FAILURE); } printf("Child process\n"); // 子进程执行V操作 sb.sem_num = 0; sb.sem_op = 1; sb.sem_flg = SEM_UNDO; if (semop(semid, &sb, 1) == -1) { perror("semop V"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } else { // 父进程执行P操作 sb.sem_num = 0; sb.sem_op = -1; sb.sem_flg = SEM_UNDO; if (semop(semid, &sb, 1) == -1) { perror("semop P"); exit(EXIT_FAILURE); } printf("Parent process\n"); // 父进程执行V操作 sb.sem_num = 0; sb.sem_op = 1; sb.sem_flg = SEM_UNDO; if (semop(semid, &sb, 1) == -1) { perror("semop V"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } return 0; } ``` 在上述代码中,创建了一个信号量集合,并将其初始化为1。然后,创建了一个子进程和一个父进程,它们分别执行P和V操作。由于信号量的初始值为1,因此父进程和子进程都可以顺利地执行。如果将信号量的初始值改为0,那么父进程和子进程都将被阻塞,直到有一个进程执行V操作为止。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值