本文共 2681 字,大约阅读时间需要 8 分钟。
在实际项目当中,经常需要把一个功能分成多个子模块实现。那么,这些子模块之间该如何关联起来呢?静态地看,模块可以看作一组完成相同功能的函数;而动态地看,模块可以是一个独立的进程、线程或者一个中断服务或者信号服务例程。根据不同的具体业务实现,它们之间可能是静态调用、动态互斥、同步、唤醒等关系。静态的调用很好实现,上层的函数调用底层的函数即可。那么,动态互斥、同步、唤醒等关系,又该如何实现呢?这就设计到我们将要讨论的信号、进程间消息通信、共享内存、线程互斥同步条件变量、RPC等手段。下面就按照Linux下的signal/semphore/mutex/cond/message/share memory/RPC的顺序逐一展开。
信号Signal机制
signal是由某个进程或者外部特殊事件触发的发送给某个进程的信号,发送者和接受者可以相同,也可以不同,接受者一旦接受到信号,预定的信号响应函数就会在中断当前进程后得到执行,完了后之前的进程进行执行。而从内核态去看,这些都是内核现有的机制去保证的。
常见的信号和含义如下:
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
signal依赖头文件是:include <signal.h>
常见的函数族包括:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signal(int signum, sighandler_t)
int kill(int pgrp, int sig)
int killpg(int pgrp, int sig);
alarm(2),
kill(2),
killpg(2),
pause(2),
sigaction(2),
signalfd(2),
sigpending(2),
sigprocmask(2),
sigsuspend(2),
bsd_signal(3),
raise(3),
siginterrupt(3),
sigqueue(3),
sigsetops(3),
sigvec(3)
sysv_signal(3)
用法示例:
#include <unistd.h>;
main()
{
unsigned int i;
alarm(1);
for(i=0;1;i++)
printf("I=%d",i);
}
SIGALRM的缺省操作是结束进程,所以程序在1秒之后结束,这样就能看到系统1s内计数的多少,从而可以感受到系统的性能。
注意事项
0.signal()系列函数处理的流程和具体的系统相关,不同的系统有不同的处理模式。
1.在多线程的环境下,它的行为是不确定的,不建议用;
2.底层实现是基于软中断,会影响当前运行的进程,因而可能会影响性能。
实际用例
1.用在进程间的同步,或者进程内部相应外部信号。
2.对某些进程屏蔽某些信号的响应;
3.为业务进程添加对特殊信号比如Ctrl+C/Ctrl+Z的处理,防止接受到这些信号后业务直接退出,导致打扫现场/di-init的操作没有机会得到执行。同时避免CPU空转, 常用的使用模式如下:
#include <stdio.h>
#include <stdint.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <semaphore.h> #include <signal.h>extern start_your_work();
extern cleanup_your_work();
static sem_t force_exit;
static void my_exithandler(int sig) { sem_post(&force_exit); } static int set_exitsignal_handler(int sig, void (*handler)(int)) { struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = handler; sigemptyset(&(sa.sa_mask)); sa.sa_flags = 0; if(sigaction(sig, &sa, NULL) == -1) { perror("sigaction"); return -1; } return 0; } int main(int argc, char * argv[]) { //mmir_monitor_thread(); if(set_exitsignal_handler(SIGHUP, my_exithandler) != 0 || set_exitsignal_handler(SIGINT, my_exithandler) != 0 || set_exitsignal_handler(SIGTERM, my_exithandler) != 0 || set_exitsignal_handler(SIGPIPE, SIG_IGN) != 0) { exit(-1); return 2; } start_your_work(); sem_wait(&force_exit); // to replace while(1);cleanup_your_work();
return 0;
}本文转自存储之厨51CTO博客,原文链接: http://blog.51cto.com/xiamachao/1784162,如需转载请自行联系原作者