专栏首页云端漫步使用信号进制实现进程通信
原创

使用信号进制实现进程通信

进程间通信方式

学习操作系统的原理,我们知道,进程间通信有以下几种方式:

  • 管道(pipe)
  • 信号(signal)
  • 消息队列
  • 共享内存
  • 信号量
  • 套接字(socket)

而在应用系统开发中,我们常用的方式就是消息队列和套接字两种方式。在程序中写了一个死循环,运行时,常使用<code>ctrl+c</code>来中断进程。突然软件卡死了,我们无法关闭,这时,你知道使用kill -9 pip来结束进程。这些基本的操作常识性操作,背后就使用的“信号量"和应用程序发生通信。

信号

信号(Signal)是Linux, 类Unix和其它POSIX兼容的操作系统中用来进程间通讯的一种方式。一个信号就是一个异步的通知,发送给某个进程,或者同进程的某个线程,告诉它们某个事件发生了。

当信号发送到某个进程中时,操作系统会中断该进程的正常流程,并进入相应的信号处理函数执行操作,完成后再回到中断的地方继续执行。

如果目标进程先前注册了某个信号的处理程序(signal handler),则此处理程序会被调用,否则缺省的处理程序被调用。

这种方式只有事件类型,不能实现进程间数据传递。

发送信号

  • kill系统调用
  • kill命令用户发送信号
  • raise库函数发送信号给当前进程 也可以通过键盘发送特定命令实现发送信号,如 ctrl+c SIGINT ctrl+z SIGTSTP ctrl+\ SIGQUIT ctrl+T SIGINFO

信号处理

程序中可以设置接受信号,编写处理函数对信号进行拦截处理,信号有以下处理动作。

其中SIGKILL和SIGSTOP不能被程序所捕捉做拦截处理

在mac电脑下,在命令终端输入<code>kill -l</code>会列出所有的signal信息

HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ VTALRM PROF WINCH INFO USR1 USR2

通过信号实现守护进程退出提示

我们现要终止一个服务进程,在终止前,让取它打印让其做个倒计时的功能。那么怎么实现这个小功能呢?这就需要用到信号,通过kill发送终止信号,在程序中编写捕捉函数,在信号被触发时,执行捕捉函数。

package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func main() {
	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGINT)
	fmt.Println("启动服务")
	sig := <-c
	fmt.Println("收到信号", sig)
	TipMsg()

	sum := 0
	for {
		sum += 1
		time.Sleep(1 * time.Second)
	}
}

func TipMsg() {
	fmt.Printf("5秒后退出程序。。。")
	for i := 5; i > 0; i-- {
		time.Sleep(1 * time.Second)
	}
	fmt.Println("退出程序")
	os.Exit(0)
}

go run server.go启动服务,按下<code>ctrl+c</code>既可完成测试,也可以使用kill发送信号进行测试。方法

$go build 
$./server
//另开一个终端tab
$ps -ef | grep server
$kill 2 pid(服务的进程id)

使用信号量实现配置文件热加载

我们在写程序时,常常将一些可控的参数通过配置文件的方式进行加载。这些参数也经常需要动态的调整,那么修改了配置文件后,就需要重新的加载配置文件,就需要重启服务。借助信号量是不就可以达到配置文件重新加载的目的。基于上边的例子,我们将TipMsg的操作改为配置文件重加载的操作,然后将信号修改为SIGUSR1, 完成修改后,使用kill -USER1 pid即可完成配置的重新加载。

具体的实现可以参考这篇文章https://segmentfault.com/a/1190000019436438

参考:

https://colobu.com/2015/10/09/Linux-Signals/

https://www.jianshu.com/p/f445bfeea40a

喜欢请关注“云端漫记", 将持续为你更

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 使用信号进制实现进程通信

    而在应用系统开发中,我们常用的方式就是消息队列和套接字两种方式。在程序中写了一个死循环,运行时,常使用 ctrl+c来中断进程。突然软件卡死了,我们无法关闭,这...

    暮雨
  • HashMap 如何解决冲突?扩容机制?

    HashMap默认的容量是DEFAULT_INITIAL_CAPACITY,16。

    暮雨
  • 深入理解unicode编码和utf-8编码区别

    计算机的世界中,充满了各种编码,编码就是将世界的事物,通过定义的一套数字规范,进而实现其可以在计算机中存储可计算。unicode码存在的目的是为了统一对世界各国...

    暮雨
  • android 休眠唤醒机制分析(一) — wake_lock【转】

    Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠,但可以进行设备的浅度休眠操作。wak...

    233333
  • TypeScript 练习题

    TypeScript 的学习资料非常多,其中也不乏很多优秀的文章和教程。但是目前为止没有一个我特别满意的。原因有:

    lucifer210
  • 函数 (一) 基础

    一、函数的作用 函数可以让我们代码结构更清晰,而且避免了代码的重复,冗余,使一段代码或者功能可以反复的被调用,大大提高了开发效率 二、函数的定义 def 函数名...

    人生不如戏
  • 现代操作系统的存储器结构

    按块读取 程序局部性原理,可以提高效率 充分发挥总线CPU针脚等一次性读取更多 数据的能力 缓存行(cache line): 缓存行越大,局部性空间效率...

    JavaEdge
  • Cypress系列(63)- 使用 Custom Commands

    注意:仅在 Cypress.Commands.add() 中支持使用options,而在 Cypress.Commands.overwrite() 中不支持使用...

    小菠萝测试笔记
  • 码农福利(一)

    整理了一些经典好书的电子书单,关注微信公众号JavaQ,并回复“JavaQ”,电子版轻松下载!码农福利将持续更新! ---- ? ? ? ? ? ? ? ? ?...

    JavaQ
  • 恶意代码分析实战总结

    (1)如果安装了VMware Tools,则使用CreateToolhelp32Snapshot、Process32Next扫描进程列表,查看是否有VMware...

    De4dCr0w

扫码关注云+社区

领取腾讯云代金券