多进程与多线程(六)

1.1.2.3           信号

信号的使用由来已久,早在UNIX中就被广泛使用。信号机制的存在,使得父子进程之间可以互相通过“置标志[1]”来通知一个或多个进程异步事件发生。

信号又称为软中断,这是因为信号机制是对硬中断的一种模拟,其处理程序运行在用户态(注意,我们需要理解用户态和核心态),所以有较大的时延。软中断通过发送规定的信号到指定进程,被指定的进程定时[2]地查询有无外来信号。

信号来自内核,也可来自一个进程,或来自进程自己。所以进程间可以互相发信号。

每一个具体的信号,用int类型定义。通常的操作系统,信号的个数都比较少,这是因为在PCB上面,记载了一个有关信号处理的标识位。这个位的标志,只有32个bit,每个bit对应一个信号(由此可见信号是不能胜任进程间专递)。

一个信号仅对应一个标志位,可见“信号”机制是多么得简洁,所以,信号仅适合于在进程间起“通知”的作用,如果进程间要交换大批数据,那么信号功能就不适用了。

在PG系统上,大量使用了信号来实现各个进程间的事件发生通知,我们来看看实例。

       首先,在src/backend/libpq/pqsignal.c中定义了pqsignal函数,实现signal的功能(注意PG8.3.1版本Windows平台下是在src/backend/port/win32/signal.c[3]中定义pqsignal函数实现的,通过定义信号数组pg_signal_array绑定信号和信号处理函数,在一个进程创建的时候,通过pg_signal_thread函数创建有名管道以便模拟进程的PCB块上的信号位,并为这个进程创建一个信号监听线程,模拟信号的监听与触发,从而实现同Linux类似的信号机制)。

其次,我们将重点看有是“谁”调用了pqsignal函数,和多进程相关的调用函数如下(还有一些地方如libpq中调用src/interfaces/libpq/pqsignal.c中的pqsignal[4]函数,这些就不多言)(如下一些看似进程的,有些生命周期很短暂):

AutoVacLauncherMain:Aotovacuum进程相关

AutoVacWorkerMain:Aotovacuum进程相关

BackgroundWriterMain:bgWrite进程

bootstrap_signals:初始化数据库时,initdb可执行程序启动的进程

PgArchiverMain:自定归档进程

PgstatCollectorMain:收集统计信息的进程

PostgresMain:用户登录后连接的数据库服务器引擎工作进程

PostmasterMain:PG的主进程,提供监听连接的作用

BackendInitialize:Perform additional initialization and collect startup packet

SysLoggerMain:系统日志进程,

WalWriterMain:预先日志进程(WAL)

       再次,查看各个进程调用pqsignal函数时给定的第二个参数是否发生作用。

       第四,查看信号何时被发送以及如何被处理。比如,归档进程的PgArchiverMain函数定义如下:

       pqsignal(SIGUSR1, pgarch_waken);

       这意味着归档进程收到SIGUSR1信号后,需要进行归档动作。

       在PG中,什么时候会主动要求日志文件进行归档呢?答案是这样的,当日志写满后,这个日志文件就可以被归档了,而写日志的是XlogWrite,所以,当WAL进程写一个日志满后,它就会通过SendPostmasterSignal函数发出一个SIGUSR1信号给归档进程,具体对应xlog.c中的XlogArchiveNotify函数。(为何SendPostmasterSignal给postmaster发信号而归档进程可接收?)

       信号在PG中使用极为频繁,每个进程都有涉及,这些信号,需要通过仔细研读才能详细掌握,多读多想,就如两条拐杖,能帮助你在PG的信号实现机制中自由翱翔。

 

题外话:

既然PG大量使用了信号机制,那么MySQL又是怎么样的呢?

这个问题很好,答案是MySQL不使用信号机制。

为什么MySQL不使用信号机制?

答案是MySQL是多线程结构。信号是进程间通信的手段之一。

 

小技巧:

在Linux系统上,如何知道我们调试的代码在某时刻的内存状态呢?有人说使用调试工具即可。可是,如果没有调试器可用,我们又该怎么办呢?答案是――核心转储。

首先,在我们需要在我们想要转储的代码处添加abort()函数,编译。

其次,执行“ulinit –c unlimited”命令(确保操作系统会转储出错进程的内存信息)。

第三,执行我们的代码,使之运行到abort()函数处,这时,查看系统,有一个core.xxxxx的文件,这个就是核心转储出来的出错进程的出错前的内存状态,xxxxx对应的是出错进程的进程号。

第四,使用“gdb 进程名 core.xxxxx”,可以查看核心转储文件的内容。

这个小技巧就是利用了abort函数给自己发出非正常终止信号来实现辅助调试功能的。

 



[1] 信号的实现,是目的进程首先关联自己PCB块上的信号标志位和对应的处理函数,源进程通过为目的进程置信号标志位实现通知,然后目的进程自己检查自己的信号标志位,识别第x标志位被置,从而激发被关联的函数,实现信号响应。

[2] 所谓定时,是指有四种情况发生:1指进程遇到时钟中断;2核心态转至用户态;3进入睡眠态之前;4它退出低优先级睡眠之时。由这四种情况可以看出,信号机制是不能保证实时要求的。

[3] 要想了解windows下信号的实现,仔细阅读src/backend/port/win32/signal.c中代码。

[4] src/interfaces/libpq/pqsignal.c和src/backend/libpq/pqsignal.c都定义了pgsignal函数,前者给外围调用libpq库的独立程序使用,如initdb,pg_dump等;后者为数据库引擎中的多进程使用。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值