1、基本概念

进程阻塞:

进程执行条件得不到满足,就自动放弃CPU资源而进入休眠状态,以等待条件满足,当条件满足时,系统就将控制权还给该进程进行未完成的操作

共享资源:

进程间协调使用的系统资源

锁定:

当某个进程使用共享资源时,可能需要防止别的进程对该资源的使用。Linux提供一些方法保证共享资源被某个进程使用时,其他进程不能使用,就称为共享资源的锁定

2、信号

信号的作用是通知一个或多个进程异步事件的发生,也可以用来处理某种严重的错误,可以从内核发往进程,也可以从一个进程发往另一个进程,

例如:用户在后台启动了一个程序,现在想要终止此进程的执行,就可以使用Kill命令将SIGTERM信号发送给这个进程,SIGTERM将终止该进程的执行

例如:执行exit()时,就向子进程的父进程发送SIGCHLD信号(子进程结束信号),若此时父进程在执行wait(),则父进程会被唤醒,若不是在执行wait(),则此父进程不会捕捉到SIGCHLD信号,该信号就不起作用,子进程进入过渡状态(如果父进程忽略SIGCHLD,子进程就会结束而不会进入过渡状态)

在大多数情况下,当进程收到一个信号时,会被正常终止,相当于进程执行了一个临时加入的exit()调用。

信号SIGQUIT、SIGILL、SIGTRAP、SIGFPE会导致一个非正常终止,它们将发生核心转贮,也就是把进程的内存映像写入进程当前目录的core文件中,core文件以二进制形式记录了终止时程序中全部变量值、硬件寄存器值和内核中的控制信息,非正常终止进程的退出状态除了其低端第7位置位外,其他与通过信号正常终止时一样

3、信号的复位

当一个信号的信号处理函数执行时,该进程又收到了同样的信号,那么该信号将会被存储而不会中断信号处理函数,直到信号处理函数执行完后重新调用相应处理函数,但是如果接收到了其他类型的信号,那么该信号处理函数将会被中断

例如:

#include <signal.h>
int interrupt()
{
printf(“Interrupt called\n”);
sleep(3);
printf(“Interrupt Func Ended.\n”);
}
main()
{
signal(SIGINT,interrupt);
printf(“Interrupt set for SIGINT\n”);
sleep(10);
printf(“Program NORMAL ended.\n”);
return;
}

  执行结果就是

Interrupt set for SIGINT
<ctrl+c>
Interrupt called
<ctrl+c>
Func Ended
Interrupt called
Func Ended
Program NORMAL ended.

  而代码:

#include <signal.h>
int interrupt()
{
printf(“Interrupt called\n”);
sleep(3);
printf(“Interrupt Func Ended.\n”);
}
int catchquit()
{
printf(“Quit called\n”);
sleep(3);
printf(“Quit ended.\n”);
}
main()
{
signal(SIGINT,interrupt);
signal(SIGQUIT,catchquit);
printf(“Interrupt set for SIGINT\n”);
sleep(10);
printf(“Program NORMAL ended.\n”);
return;
}

  执行的结果是

Interrupt set for SIGINT
<ctrl+c>
Interrupt called
<ctrl+\>
Quit called
Quit ended.
Interrupt Func Ended.
Program NORMAL ended.

  还有就是同一种信号不能累积,如:

Interrupt set for SIGINT
<ctrl+c>
Interrupt called
<ctrl+c><ctrl+c><ctrl+c>
Func Ended
Interrupt called
Func Ended
Program NORMAL ended.

  如果两个信号同时产生,系统不保证进程接收的顺序,因此,信号处理的顺序就不可控

4、进程间发送信号

一个进程可以通过signal()调用来处理其他进程发送来的信号,同时也可以通过kill(pid_t pid,int sig)来向其他进程发送信号。pid指定了信号发送的对象进程。可以是进程标识符,也可以是以下的值

1)pid = 0,  则信号被发送到当前进程所在的进程组的所有进程

2)pid = -1, 则信号按进程标识符从高到低的顺序发送给全部的进程

3)pid < -1,则信号被发送给标识符为pid 绝对值的进程组里的所有进程

信号发送的限制:普通用户进程只能向具有与其相同的用户标识符的进程发送信号,也就是说一个用户的进程不能向另一个用户的进程发送信号,只有root用户的进程才能给任何进程发送信号。

由于Kill需要知道目标进程标识符,所以一般在父子进程之间进行信号发送

举个例子:两个进程,通过发送SIGUSER1实现同步,两个进程都处于死循环中,接收对方信号前,处于暂停等待中,也就是pause(),使得程序暂停一直到信号达到,然后进程输出信息,并用kill发送一个信号给对方,若用户按了中断键,两个进程终止

#include <signal.h>
int ntimes = 0;
main()
{
int pid,ppid;
int p_action(), c_action();
/* 设定父进程的SIGUSR1 */
signal(SIGUSR1,p_action);
switch(pid = fork())
{
case -1: /*fork 失败*/
perror("synchro");
exit(1);
case 0: /*子进程模块*/
/* 设定子进程的SIGUSR1 */
signal(SIGUSR1,c_action);
/* 获得父进程的标识符 */
ppid = getppid();
for(;;)
{
sleep(1);
kill(ppid,SIGUSR1);
pause();
}
/*死循环*/
break;
default: /*父进程模块*/
for (;;)
{
pause();
sleep(1);
kill(pid,SIGUSR1);
}
/*死循环*/
}
}
int p_action()
{
printf("Patent caught signal #%d\n",++ntimes);
}
int c_action()
{
printf("Child caught signal #%d\n",++ntimes);
}

  运行结果就是

Patent caught signal #1
Child caught signal #1
Patent caught signal #2
Child caught signal #2
Patent caught signal #3
Child caught signal #3
Patent caught signal #4
Child caught signal #4
<ctrl+c>

  

Linux网络编程学习(五) ----- 信号(第四章)的更多相关文章

  1. Linux网络编程学习(六) ----- 管道(第四章)

    1.管道的定义 管道就是将一个程序的输出和另外一个程序的输入连接起来的单向通道,比如命令: ls -l|more,就建立了一个管道,获取ls -l的输出作为more的输入,数据就沿着管道从管道的左边流 ...

  2. Linux网络编程学习(十) ----- Socket(第六章)

    前言:由于第五章主要介绍了TCP和UDP协议以及两者的包头的字段以及相应的功能,这里就不介绍了,对着字段看功能就好了,后续开始学习第六章 1.Socket Socket实质上就是提供了通信的端点,每个 ...

  3. Linux网络编程学习计划

    由于网络编程是很重要的一块,自己这一块也比较欠缺,只知道一些皮毛,从今天开始系统学习<Linux网络编程>一书,全书分为十四个章节: 第一章   概论   P1-16 第二章   UNIX ...

  4. Linux网络编程学习路线

    转载自:https://blog.csdn.net/lianghe_work/article 一.网络应用层编程   1.Linux网络编程01——网络协议入门 2.Linux网络编程02——无连接和 ...

  5. Linux网络编程学习(十二) ----- 结语

    该书提前看完了,重点看了第四章和第六章,第七章以后只是大致浏览了一下,如果以后工作中涉及这一块再仔细研究一下,大概花了二十天的样子,主要了解了进程间的通信方式.socket编程以及五种I/O模式,看的 ...

  6. Linux网络编程学习(九) ----- 消息队列(第四章)

    1.System V IPC System V中引入的几种新的进程间通信方式,消息队列,信号量和共享内存,统称为System V IPC,其具体实例在内核中是以对象的形式出现的,称为IPC 对象,每个 ...

  7. Linux网络编程学习(十一) ----- 五种I/O模式(第六章)

    1.五种I/O模式是哪几个? 阻塞I/O,非阻塞I/O,I/O多路复用,信号驱动I/O(SIGIO),异步I/O 一般来讲程序进行输入操作有两个步骤,一是等待有数据可读,二是将数据从系统内核中拷贝到程 ...

  8. Linux网络编程学习(七) ----- 有名管道(第四章)

    1.什么是有名管道?为什么有了管道还需要有名管道? 有名管道是解决管道不能提供非父子进程间通信的缺陷.管道在Linux系统内部是以文件节点(inode)的形式存在,但由于其对外的不可见性(“无名”性) ...

  9. Linux网络编程学习(四) -----守护进程的建立(第三章)

    本文介绍一个例程daemon_init() #include <sys/types.h> #include <signal.h> #include <unistd.h&g ...

随机推荐

  1. video自动填充满父级元素

    想要video能自动填充慢父div的大小,只要给video标签加上style="width= 100%; height=100%; object-fit: fill"即可. obj ...

  2. CSS3 transform变形(3D转换)

    一.三维坐标 空间中三维坐标如下图所示: 向上为-Y,向下为+Y,向左为-X,向右为+X,向前为+Z,向后为-Z. 二.perspective(n)为 3D 转换元素定义透视视图 perspectiv ...

  3. python中time模块常用功能

    import time time模块提供了大量对时间进行处理的方法 time.time() # 获取当前时间戳,得到自1970年开始的秒数 >>>time.time() 155487 ...

  4. ORA-02275: 此表中已经存在这样的引用约束条件

    问题描述: 针对这个问题,发表一下我的观点.emp表和dept表使用hibernate关联查询时报的错,使用的是非注解形式,和其他一样.他们各自有entity,各自有一个hbm.xml文件,emp表这 ...

  5. apache开启验证登录

    对某个目录开启验证登录 <Directory /var/www/html/admin > AllowOverride All Order allow,deny Allow from all ...

  6. 【C++】atof()

    转自:https://blog.csdn.net/zhaoyl03/article/details/8176387 atof 是ascII to float的缩写,它将ascII字符串转换为相应的单精 ...

  7. 【fork/join】java并发编程-fork/join示例

    package com.chinamobile.epic.tako.common.graphite.query.sync.impl; import com.google.common.collect. ...

  8. react使用ant-design组件库

    新建项目并引入组件 1,全局安装脚手架 npm install -g create-react-app 2,新建项目 create-react-app reactantd 3,安装组件 npm ins ...

  9. Kafka 配置安装

    1.从官网下载安装包 http://kafka.apache.org/downloads2.上传到01虚拟机,解压3.进入安装目录下的config目录4.对server.properties进行配置 ...

  10. C++ Programming Language中的narrow_cast实现

    在C++中,各种数值类型的转化是C++编译过程中警告的主要来源,但是,很多时候,我们需要使用各种数值类型,例如我们用数组的某一位表示大小为对应序号的值,这种情况下,经常会涉及多种数值类型.根据C++ ...