美文网首页
1-4节linux系统编程——进程通信信号和创建线程

1-4节linux系统编程——进程通信信号和创建线程

作者: 赋闲 | 来源:发表于2017-01-08 15:57 被阅读0次

    通信信号

    信号:一种异步通信机制
    系统支持的信号都有默认的处理方式
    常用的信号及其处理:SIGINT | SIGQUIT | SIGALRM | SIGCHLD |
    常用信号及其处理方式:默认处理,忽略,自定义信号处理函数
    注意:信号处理函数中不要做耗时的操作
    注册信号处理函数:signal , sigaction
    发送信号:kill , 组合键

    线程创建和调度

    线程是程序执行的某一条指令流的影像
    线程函数:用于提供线程执行的指令(代码)
    线程库:pthread
    线程的创建:pthread_create
    线程等待获取线程返回值:pthread_join
    获取线程自身的线程ID:pthread_self
    判断是否是同一个线程:pthread_equal
    取消指定线程:pthread_cancel

    2)进程通信

    进程通信是进程之间相互通信或操作的一种方式
    信号机制是异步的
    信号依靠值来区分

    2.1)当信号发生时,用户可以要求进程以下列3种方式之一对信号做出响应。

    1、 捕捉信号:对于要捕捉的信号,可以为其指定信号处理函数,信号发生时该函数自动被调用,在该函数内部实现对该信号的处理。
    2、 忽略信号:大多数信号都可使用这种方式进行处理,但是SIGKILL和SIGSTOP这两个信号不能被忽略,同时这两个信号也不能被捕获和阻塞。此外,如果忽略某某些由硬件异常产生的信号(如非法存储访问或除以0),则进程的行为是不可预测的。
    3、 按照系统默认方式处理。大部分信号的默认操作是终止进程,且所有的实时信号的默认动作都是终止进程。

    2.2)信号的优先级

    信号实质上是软中断,中断有优先级,信号也有优先级。如果一个进程有多个未决信号,则对于同一个未决的实时信号,内核将按照发送的顺序来递送信号。如果存在多个未决信号,则值(或者说编号)越小的越先被递送。如果即存在不可靠信号,又存在可靠信号(实时信号),虽然POSIX对这一情况没有明确规定,但Linux系统和大多数遵循POSIX标准的操作系统一样,将优先递送不可靠信号。

    2.3)SIG信号

    信号的值定义在signal.h中,在Linux中没有16和32这两个信号。上面信号的含义如下:

    (1) SIGHUP:当用户退出Shell时,由该Shell启的发所有进程都退接收到这个信号,默认动作为终止进程。
    (2) SIGINT:用户按下组合键时,用户端时向正在运行中的由该终端启动的程序发出此信号。默认动作为终止进程。
    (3) SIGQUIT:当用户按下组合键时产生该信号,用户终端向正在运行中的由该终端启动的程序发出此信号。默认动作为终止进程并产生core文件。
    (4) SIGILL :CPU检测到某进程执行了非法指令。默认动作为终止进程并产生core文件。
    (5) SIGTRAP:该信号由断点指令或其他trap指令产生。默认动作为终止进程并产生core文件。
    (6) SIGABRT:调用abort函数时产生该信号。默认动作为终止进程并产生core文件。
    (7) SIGBUS:非法访问内存地址,包括内存地址对齐(alignment)出错,默认动作为终止进程并产生core文件。
    (8) SIGFPE:在发生致命的算术错误时产生。不仅包括浮点运行错误,还包括溢出及除数为0等所有的算术错误。默认动作为终止进程并产生core文件。
    (9) SIGKILL:无条件终止进程。本信号不能被忽略、处理和阻塞。默认动作为终止进程。它向系统管理员提供了一种可以杀死任何进程的方法。
    (10) SIGUSR1:用户定义的信号,即程序可以在程序中定义并使用该信号。默认动作为终止进程。
    (11) SIGSEGV:指示进程进行了无效的内存访问。默认动作为终止进程并使用该信号。默认动作为终止进程。
    (12) SIGUSR2:这是另外一个用户定义信号,程序员可以在程序中定义并使用该信号。默认动作为终止进程。
    (13) SIGPIPE:Broken pipe:向一个没有读端的管道写数据。默认动作为终止进程。
    (14) SIGALRM:定时器超时,超时的时间由系统调用alarm设置。默认动作为终止进程。
    (15) SIGTERM:程序结束(terminate)信号,与SIGKILL不同的是,该信号可以被阻塞和处理。通常用来要求程序正常退出。执行Shell命令kill时,缺少产生这个信号。默认动作为终止进程。
    (16) SIGCHLD:子程序结束时,父进程会收到这个信号。默认动作为忽略该信号。
    (17) SIGCONT:让一个暂停的进程继续执行。
    (18) SIGSTOP:停止(stopped)进程的执行。注意它和SIGTERM以及SIGINT的区别:该进程还未结束,只是暂停执行。本信号不能被忽略、处理和阻塞。默认作为暂停进程。
    (19) SIGTSTP:停止进程的动作,但该信号可以被处理和忽略。按下组合键时发出该信号。默认动作为暂停进程。
    (20) SIGTTIN:当后台进程要从用户终端读数据时,该终端中的所有进程会收到SIGTTIN信号。默认动作为暂停进程。
    (21) SIGTTOU:该信号类似于SIGTIN,在后台进程要向终端输出数据时产生。默认动作为暂停进程。
    (22) SIGURG:套接字(socket)上有紧急数据时,向当前正在运行的进程发出此信号,报告有紧急数据到达。默认动作为忽略该信号。
    (23) SIGXCPU:进程执行时间超过了分配给该进程的CPU时间,系统产生该信号并发送给该进程。默认动作为终止进程。
    (24) SIGXFSZ:超过文件最大长度的限制。默认动作为yl终止进程并产生core文件。
    (25) SIGVTALRM:虚拟时钟超时时产生该信号。类似于SIGALRM,但是它只计算该进程占有用的CPU时间。默认动作为终止进程。
    (26) SIGPROF:类似于SIGVTALRM,它不仅包括该进程占用的CPU时间还抱括执行系统调用的时间。默认动作为终止进程。
    (27) SIGWINCH:窗口大小改变时发出。默认动作为忽略该信号。
    (28) SIGIO:此信号向进程指示发出一个异步IO事件。默认动作为忽略。
    (29) SIGPWR:关机。默认动作为终止进程。
    (30) SIGRTMIN~SIGRTMAX:Linux的实时信号,它没有固定的含义(或者说可以由用户自由使用)。注意,Linux线程机制使用了前3个实时信号。所有的实时信号的默认动作都是终止进程

    3)线程

    了解 C10K问题
    一条进程带一万条线程连接
    解决方案
    解决这一问题,主要思路有两个:
    每个进程/线程处理一个连接
    每个进程/线程同时处理多个连接(IO多路复用)
    这些操作系统提供的功能就是为了解决C10K问题:FreeBSD推出了kqueue,Linux推出了epoll,Windows推出了IOCP,Solaris推出了/dev/poll。

    了解两个网站
    stackoverflow
    segmentfault

    进程控制块 PCB区
    栈区
    堆区(堆区和栈区相向增长)
    数据区(全局变量)(多线程共享数据区)
    文本区

    4)pthread族函数

    4.1)创建线程

    pthread_create
    pthread头文件
    #include <pthread.h>
    参数
    int pthread_create ( pthread_t *thread, const pthread_attr_t *attr,void (start_routine) (void *), void *arg );
    Compile and link with -pthread.
    编译时加上 -lpthread 或 -pthread

    4.2)pthread_join
    int pthread_join(pthread_t thread, void **retval);
    

    //函数pthread_join用来等待一个线程的结束,线程间同步的操作

    4.3)pthread_exit
      void pthread_exit(void *retval);
    

    //线程通过调用pthread_exit函数终止执行,就如同进程在结束时调用exit函数一样。这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针。

    4.4)pthread_cancel

    是计算机语言,它发送终止信号给thread线程,如果成功则返回0,否则为非0值

    4.6)pthread_self

    pthread_self 是一种函数,功能是获得线程自身的ID

    4.7)pthread_cond_wait

    条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起

    程序

    信号处理函数

    #include<stdio.h>
    #include<unistd.h>
    #include<signal.h>
    #include<time.h>
    
    void sig_handle(int signo)
    {
        switch(signo)
        {
            case SIGINT:
                printf("%d",getpid());
                break;
        }
    }
    
    int main (int argc ,char *argv[])
        {
        pid_t pid;
        signal(SIGINT , SIG_ING);//忽略信号
        signal(SIGINT, sig_handle);//显示信号
        signal(SIGINT, SIG_DFT);//默认信号
    
        pid = fork() ;
    
        while(1)
        {
            sleep(2);
            printf("befor \n");
        }
    
        return 0 ;
    }
    

    父子进程信号通讯

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<signal.h>
    //练习2:创建一个子进程,子进程进入一个无限的循环,模拟一秒从数据中心取一个数据并处理的
    //过程,直到子进程收到父进程发送过来的SIGUSR1信号,打印子进程pid,并退出
    //父进程:创建子进程之后,循环等待信号的到达,当收到SIGINT(由组合键ctrl+c模拟)信号
    //之后,向子进程发送一个SIGUSR1信号
    
    pid_t pid;
    
    void parent_sig_handler(int signo);
    void child_sig_handler(int signo);
    
    int main (int argc , char *argv[])
    {
    signal(SIGINT , parent_sig_handler);//显示父程序的信号
    if((pid = fork()) == 0)
    {
            while(1)
            {
            int client_id = 0;
            signal(SIGINT,SIG_IGN);     //忽略信号
            signal(SIGINT ,child_sig_handler ); //显示子程序的信号
                while(1)
                {
                client_id=rand()%100+1;
                printf("client in %d\n",client_id);
                sleep(1);
                printf("client out %d\n",client_id);
                }
            }
    }
    else if(pid > 0)
        {
        while(1);
        }
    
    return 0;
    }
    //父程序
    void parent_sig_handler(int signo)
    {
    switch(signo)
        {
        case SIGCHLD:
            wait(NULL);
            break;
        case SIGINT :
            //kill函数向指定 进程发送指定信号值
            //注意,信号发送无法传递数据
            kill (pid, SIGUSR1);
            break;
        default:
            break;
        }
    }
    //子程序
    void child_sig_handler(int signo)
    {
    if(signo == SIGUSR1)
        {
        printf(child pid"%d\n",getpid() );
        exit(0);
        }
    }
    

    相关文章

      网友评论

          本文标题:1-4节linux系统编程——进程通信信号和创建线程

          本文链接:https://www.haomeiwen.com/subject/uscxbttx.html