进线程通信之信号机制

简介:

    在实际项目当中,经常需要把一个功能分成多个子模块实现。那么,这些子模块之间该如何关联起来呢?静态地看,模块可以看作一组完成相同功能的函数;而动态地看,模块可以是一个独立的进程、线程或者一个中断服务或者信号服务例程。根据不同的具体业务实现,它们之间可能是静态调用、动态互斥、同步、唤醒等关系。静态的调用很好实现,上层的函数调用底层的函数即可。那么,动态互斥、同步、唤醒等关系,又该如何实现呢?这就设计到我们将要讨论的信号、进程间消息通信、共享内存、线程互斥同步条件变量、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,如需转载请自行联系原作者




相关文章
|
8月前
|
Java
实现Java多线程中的线程间通信
实现Java多线程中的线程间通信
|
9月前
|
Java 程序员
从菜鸟到大神:JAVA多线程通信的wait()、notify()、notifyAll()之旅
【6月更文挑战第21天】Java多线程核心在于wait(), notify(), notifyAll(),它们用于线程间通信与同步,确保数据一致性。wait()让线程释放锁并等待,notify()唤醒一个等待线程,notifyAll()唤醒所有线程。这些方法在解决生产者-消费者问题等场景中扮演关键角色,是程序员从新手到专家进阶的必经之路。通过学习和实践,每个程序员都能在多线程编程的挑战中成长。
82 6
|
5月前
|
Java 调度
[Java]线程生命周期与线程通信
本文详细探讨了线程生命周期与线程通信。文章首先分析了线程的五个基本状态及其转换过程,结合JDK1.8版本的特点进行了深入讲解。接着,通过多个实例介绍了线程通信的几种实现方式,包括使用`volatile`关键字、`Object`类的`wait()`和`notify()`方法、`CountDownLatch`、`ReentrantLock`结合`Condition`以及`LockSupport`等工具。全文旨在帮助读者理解线程管理的核心概念和技术细节。
67 1
[Java]线程生命周期与线程通信
|
4月前
|
Java
JAVA多线程通信:为何wait()与notify()如此重要?
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是实现线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件满足时被唤醒,从而确保数据一致性和同步。相比其他通信方式,如忙等待,这些方法更高效灵活。 示例代码展示了如何在生产者-消费者模型中使用这些方法实现线程间的协调和同步。
61 3
|
9月前
|
Java
Java Socket编程与多线程:提升客户端-服务器通信的并发性能
【6月更文挑战第21天】Java网络编程中,Socket结合多线程提升并发性能,服务器对每个客户端连接启动新线程处理,如示例所示,实现每个客户端的独立操作。多线程利用多核处理器能力,避免串行等待,提升响应速度。防止死锁需减少共享资源,统一锁定顺序,使用超时和重试策略。使用synchronized、ReentrantLock等维持数据一致性。多线程带来性能提升的同时,也伴随复杂性和挑战。
155 0
|
5月前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
53 1
|
5月前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
106 1
|
5月前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
85 1
|
5月前
|
Java
|
5月前
多线程通信和同步的方式有哪些?
【10月更文挑战第6天】
248 0

热门文章

最新文章

相关实验场景

更多