Android C++系列(Linux信号)

怀抱观古今,寝食展戏谑。这篇文章主要讲述Android C++系列:Linux信号相关的知识,希望能为你提供帮助。
?
可重入函数

  • 不含全局变量和静态变量是可重入函数的一个要素
  • 可重入函数见man 7 signal
  • 在信号捕捉函数里应使用可重入函数
  • 在信号捕捉函数里禁止调用不可重入函数
例如:strtok就是一个不可重入函数,因为strtok内部维护了一个内部静态指针,保存上一 次切割到的位置,如果信号的捕捉函数中也去调用strtok函数,则会造成切割字符串混乱, 应用strtok_r版本,r表示可重入。
信号引起的竞态和异步I/O时序竞态
  • ??int pause(void) ??
  • 使调用进程挂起,直到有信号递达,如果递达信号是忽略,则继续挂起
  • ??int sigsuspend(const sigset_t *mask) ??
  • 以通过指定mask来临时解除对某个信号的屏蔽,
  • 然后挂起等待,
  • 当被信号唤醒sigsuspend返回时,进程的信号屏蔽字恢复为原来的值
mysleep实现,这种实现方式是否存在BUG?
#include < unistd.h>
#include < signal.h>
#include < stdio.h>
void sig_alrm(int signo)
/* nothing to do */

unsigned int mysleep(unsigned int nsecs)
struct sigaction newact, oldact;
unsigned int unslept;
newact.sa_handler = sig_alrm;
sigemptyset(& newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGALRM, & newact, & oldact);
alarm(nsecs);
pause();
unslept = alarm(0);
sigaction(SIGALRM, & oldact, NULL);
return unslept;

int main(void)
while(1)
mysleep(2);
printf("Two seconds passed\\n");

return 0;

mysleep改进版
unsigned int mysleep(unsigned int nsecs)
struct sigaction newact, oldact;
sigset_t newmask, oldmask, suspmask;
unsigned int unslept;
/* set our handler,save previous information */
newact.sa_handler = sig_alrm;
sigemptyset(& newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGALRM, & newact, & oldact);
/* block SIGALRM and save current signal mask */
sigemptyset(& newmask);
sigaddset(& newmask, SIGALRM);
sigprocmask(SIG_BLOCK, & newmask, & oldmask);
alarm(nsecs);
suspmask = oldmask;
sigdelset(& suspmask, SIGALRM); /* make sure SIGALRM isnt blocked */
sigsuspend(& suspmask); /* wait for any signal to be caught */
/* some signal has been caught,SIGALRM is now blocked */
unslept = alarm(0);
sigaction(SIGALRM, & oldact, NULL); /* reset previous action */

/* reset signal mask, which unblocks SIGALRM */
sigprocmask(SIG_SETMASK, & oldmask, NULL);
return(unslept);

全局变量异步I/O
可重入函数
  1. 不含全局变量和静态变量是可重入函数的一个要素
  2. 可重入函数见man 7 signal
  3. 在信号捕捉函数里应使用可重入函数
避免异步I/O的类型
  • sig_atomic_t 平台下的原子类型
  • volatile 防止编译器开启优化选项时,优化对内存的读写
SIGCHLD信号处理SIGCHLD的产生条件
  • 子进程终止时
  • 子进程接收到SIGSTOP信号停止时
  • 子进程处在停止态,接受到SIGCONT后唤醒时
代码实现
#include < stdio.h>
#include < stdlib.h>
#include < unistd.h>
#include < errno.h>
#include < sys/types.h>
#include < sys/wait.h>
#include < signal.h>
void sys_err(char *str)
perror(str);
exit(1);

void do_sig_child(int signo)
int status;
pid_t pid;
while ((pid = waitpid(0, & status, WNOHANG)) > 0)
if (WIFEXITED(status))
printf("child %d exit %d\\n", pid, WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("child %d cancel signal %d\\n", pid, WTERMSIG(status));


int main(void)
pid_t pid;
int i;
//阻塞SIGCHLD
for (i = 0; i < 10; i++)
if ((pid = fork()) == 0)
break;
else if (pid < 0)
sys_err("fork");

if (pid == 0)
int n = 18; while (n--)
printf("child ID %d\\n", getpid());
sleep(1);

return i;
else if (pid > 0)//先设置捕捉
//再解除对SIGCHLD的阻塞
struct sigaction act;
act.sa_handler = do_sig_child;
sigemptyset(& act.sa_mask); act.sa_flags = 0;
sigaction(SIGCHLD, & act, NULL);
while (1)
printf("Parent ID %d\\n", getpid());
sleep(1);


return 0;

status处理方式
??pid_t waitpid(pid_t pid, int *status, int options) ??
  • options
  • WNOHANG 没有子进程结束,立即返回
  • WUNTRACED
  • 如果子进程由于被停止产生的SIGCHLD, waitpid则立即返回
  • WCONTINUED 如果子进程由于被SIGCONT唤醒而产生的SIGCHLD, waitpid则立即返回
  • 获取status
  • WIFEXITED(status) 子进程正常exit终止,返回真 WEXITSTATUS(status)返回子进程正常退出值
  • WIFSIGNALED(status) 子进程被信号终止,返回真
  • WTERMSIG(status)返回终止子进程的信号值 WIFSTOPPED(status)
  • 子进程被停止,返回真 WSTOPSIG(status)返回停止子进程的信号值
  • WIFCONTINUED(status) 子进程由停止态转为就绪态,返回真
向信号捕捉函数传参sigqueue
int sigqueue(pid_t pid, int sig, const union sigval value) union sigval
int sival_int;
void *sival_ptr; ;

sigaction
void (*sa_sigaction)(int, siginfo_t *, void *)
siginfo_t
int si_int;
void *si_ptr;
sigval_t si_value;
...

sa_flags = SA_SIGINFO
/* POSIX.1b signal */ /* POSIX.1b signal */ /* Signal value */

实例
  • 进程自己收发信号,在同一地址空间
  • 不同进程间收发信号,不在同一地址空间,不适合传地址
信号中断系统调用read阻塞时,信号中断系统调用:
  1. 返回部分读到的数据
  2. read调用失败,errno设成EINTER
总结【Android C++系列(Linux信号)】本文介绍了可重入函数,信号引起的竞态和异步I/O,SIGCHLD信号处理,向想好捕捉函数传参,信号中断系统调用。

    推荐阅读