首页 > 系统相关 >Linux 进程与线程、线程与信号

Linux 进程与线程、线程与信号

时间:2022-10-21 19:24:58浏览次数:38  
标签:__ set int void Linux 线程 pthread 进程

进程与线程

多线程程序调用fork后,子进程只是调用fork线程的完整复制。子进程自动继承父进程种互斥锁的状态。这引起一个问题:子进程不知道从父进程继承来的互斥锁的具体状态。这个互斥锁可能被加锁了,但不是调用fork函数的那个线程锁住的,而是由其他线程锁住的。

/*
prepare 在fork调用后创建子进程前被执行,用于锁住父进程种互斥锁
parent 在fork创建出子线程后,fork返回前在父进程中被执行,所用是释放被锁住的互斥锁
child 在fork返回前在子进程中执行,也是用于释放在prepare中被锁住的互斥锁
成功时返回0,失败返回错误码
*/
extern int pthread_atfork (void (*__prepare) (void),
			   void (*__parent) (void),
			   void (*__child) (void)) __THROW;


void prepare() {
  pthread_mutex_lock(&mutex);
}
void infork() {
  pthread_mutex_unlock(&mutex);
}
pthread_atfork(prepare, infork, infork);

线程与信号

每个线程可独立设置信号掩码

// 设置进程线程信号掩码
extern int sigprocmask (int __how, const sigset_t *__restrict __set,
			sigset_t *__restrict __oset) __THROW;
// 设置线程线程信号掩码
extern int pthread_sigmask (int __how,
			    const __sigset_t *__restrict __newmask,
			    __sigset_t *__restrict __oldmask)__THROW;

// 向进程发信号
extern int kill (__pid_t __pid, int __sig) __THROW;
// 向线程发信号
// 当sig为0时步发送信号,但仍会执行错误检查,可用于检测目标线程是否存在
extern int pthread_kill (pthread_t __threadid, int __signo) __THROW;

// 用于进程
extern int sigqueue (__pid_t __pid, int __sig, const union sigval __val) __THROW;
// 用于线程
extern int pthread_sigqueue (pthread_t __threadid, int __signo,
			     const union sigval __value) __THROW;

进程中所有线程共享该进程信号,线程库根据线程掩码决定将信号发给哪个线程。因此在每个子线程单独设置线程掩码会导致逻辑错误。此外,所有线程共享信号处理函数,也就是在一个线程中设置某个信号处理函数后会覆盖其他线程的同一信号处理函数。这2点说明我们应该定义一个专门的线程用于处理所有信号

  1. 在创建子线程前调用pthread_sigmask设置信号掩码,所有新子线程都会继承这个掩码。时候所有线程都不会相应被屏蔽信号
  2. 在某个线程中调用以下函数等待信号并处理
    extern int sigwait (
        const sigset_t *__restrict __set, 
        int *__restrict __sig
    ) __nonnull ((1, 2));

    可以简单的将set设置为第1步指定的被屏蔽的信号,sig参数用于存储收到的信号值。成功返回0,失败返回错误码。如果使用了sigwait,就不应该再使用信号处理函数。

     #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>
    #include <errno.h>
    
    /* Simple error handling functions */
    
    #define handle_error_en(en, msg) \
        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
    
    static void *
           sig_thread(void *arg)
    {
        sigset_t *set = arg;
        int s, sig;
    
        for (;;) {
            s = sigwait(set, &sig);
            if (s != 0)
                handle_error_en(s, "sigwait");
            printf("Signal handling thread got signal %d\n", sig);
        }
    }
    
    int main(int argc, char *argv[])
    {
        pthread_t thread;
        sigset_t set;
        int s;
    
        /* Block SIGQUIT and SIGUSR1; other threads created by main() will inherit a copy of the signal mask. */
    
        sigemptyset(&set);
        sigaddset(&set, SIGQUIT);
        sigaddset(&set, SIGUSR1);
        s = pthread_sigmask(SIG_BLOCK, &set, NULL);
        if (s != 0)
            handle_error_en(s, "pthread_sigmask");
    
        s = pthread_create(&thread, NULL, &sig_thread, (void *) &set);
        if (s != 0)
            handle_error_en(s, "pthread_create");
    
        /* Main thread carries on to create other threads and/or do other work */
        pause();            /* Dummy pause so we can test program */
    }

 

标签:__,set,int,void,Linux,线程,pthread,进程
From: https://www.cnblogs.com/zhh567/p/16808097.html

相关文章

  • linux shell中利用关键字批量移动或复制文件
     001、[root@localhosttest3]#lsa34a45b34b54c23c34dirab[root@localhosttest3]#tree.├──a34├──a45├──b34├──b54├──c23......
  • 进程和线程的区别
    一:什么是线程:线程是操作系统能够进行运算调度的最小单元。它被包含在进程中,是进程中实际运行的单位。一个进程中可以并发多个线程,每个线程执行不同的任务。二;什么是进......
  • Linux/Ubuntu命令行登陆和退出postgres数据库
    1.登陆sudo-i-upostgrespostgres@eisen:~$psqlpsql(14.5(Ubuntu14.5-2.pgdg20.04+2),服务器12.12(Ubuntu12.12-0ubuntu0.20.04.1))输入"help"来获取帮助......
  • java 线程详解
    线程目录HelloWorld在Java中有两种方式创建线程,第一种方式是实现​​Runnable​​​接口,第二种方式是继承​​Thread​​类,下面是使用示例:publicclassRunnableDe......
  • linux 查看网卡型号(grep -A 1 用法)
    需要grep-A1显示多一行,否则显示一行只能看到芯片组型号lspci-v|grepEthernet-A13b:00.0Ethernetcontroller:MellanoxTechnologiesMT27800Family[Connect......
  • Linux-history 命令的介绍与使用
    Linux-history命令的介绍与使用介绍在linux下面可以使用history命令查看用户的所有历史操作,同时shell命令操作记录默认保存在用户目录的.bash_history文件中......
  • FastReport OpenSource发布到Linux上的准备
    一、安装libgdiplus(libgdiplus是一个Mono库,用于对非Windows操作系统提供GDI+兼容的API) apt-getinstallbuild-essentiallibgtk2.0-devapt-getinstalllibgif-dev......
  • 进程与线程的区别
    一.进程与线程1.进程一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一......
  • Linux系统下修改KVM虚拟机配置
    一、安装虚拟机1、设备重启进入BIOS,打开SMMU。F10保存退出2、进入系统后安装线管组件virt-installqemu-kvmqemu-imgvirt-managerlibvirtlibvir......
  • 进程与线程的区别
    一、进程的线程的概念进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。 线程:是进程的一个执行单元,是进程内......