Linux下的程序、进程和线程

Linux下的程序、進程和線程

本文偏向於實際Unix環境下的進程和線程的操作函數的學習,只涉及部分的理論。


概念

  1. Linux環境下的進程

    • 進程的產生

      • 複製父進程的環境配置
      • 在內核中建立進程結構
      • 將結構插入進程列表
      • 分配資源
      • 複製父進程的內存映射信息
      • 管理文件描述符和鏈接點
      • 通知父進程
    • 進程的終止

      • main函數返回
      • 調用exit
      • 調用_exit
      • 調用abort
      • 由一個信號終止

      進程終止將釋放其擁有的資源

  2. 線程和進程的主要區別是進程是操作系統資源分配的基本單位,擁有完整的虛擬空間。

    線程則除了CPU資源,所有的資源都是要與進程中的其他線程共享資源,不單獨分配資源。


進程產生的方式

以下函數大部分都要導入

#include <sys/types.h> //包含了大部分的引申的數據類型的庫,如ssize_t,pid_t等
#include <unistd.h> //unix standard library
  1. 進程號

    getpid()、getppid()函數

    前者返回當前進程的id,後者返回當前進程的父進程的id。返回值類型都為pid_t

  2. 複製進程fork()

    fork()函數產生一個新的進程,除了內存之外,其他的信息都與調用該函數進程共享,包括程序計數器,所以在fork後父進程和子進程同步執行接下來的指令。

    在父進程中,fork函數的返回值為子進程的id,在子進程中則返回0

  3. system()方式

    system()函數可以在C語言程序中使用外部的shell命令。

    int system(const char * cmdstring)
    {
        pid_t pid;
        int status;
     
    if(cmdstring == NULL)
    {
        return (1); //如果cmdstring为空,返回非零值,一般为1
    }
     
    if((pid = fork())<0)
    {
        status = -1; //fork失败,返回-1
    }
    else if(pid == 0) //子进程
    {
        execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
        _exit(127); // exec执行失败返回127,注意exec只在失败时才返回现在的进程,成功的话现在的进程就不存在啦~~
    }
    else //父进程
    {
        while(waitpid(pid, &status, 0) < 0)
        {
            if(errno != EINTR)
            {
                status = -1; //如果waitpid被信号中断,则返回-1
                break;
            }
        }
    }
     
        return status; //如果waitpid成功,则返回子进程的返回状态
    }
    
    

    system()源碼如上。在調用system函數後會產生兩個進程,子進程調用execl函數(execl內部執行系統調用execve())執行shell命令,父進程則阻塞等待子進程的執行。

  4. 進程執行exec()函數系列

    之前的fork()和system()函數都是新建一個進程來執行操作。exec()族函數則是用新進程代替原來的進程,系統從新進程運行,PID值不變。

  5. 初始進程init

    所有進程的祖先,original process


進程間通信與同步

管道

管道是由内核管理的一个缓冲区,管道的一端连接一个进程的输出,另一端连接一个进程的输入。

在Linux中,管道的实现没有专门的数据结构,而是借助了文件系统的file结构和VFS的索引节点inode。通过将两个 file 结构指向同一个临时的 VFS 索引节点,而这个 VFS 索引节点又指向一个物理页面而实现的。如下图

管道读写时,管道的写函数通过将字节复制到VFS索引节点指向的物理内存而写入数据,管道的读函数就可以通过复制物理内存中的字节而读出数据。

当写进程向管道中写入时,它利用标准的库函数write(),系统根据库函数传递的文件描述符,可找到该文件的 file 结构。file 结构中指定了用来进行写操作的函数(即写入函数)地址,于是,内核调用该函数完成写操作。写入函数在向内存中写入数据之前,必须首先检查 VFS 索引节点中的信息,同时满足如下条件时,才能进行实际的内存复制工作:

  • 内存中有足够的空间可容纳所有要写入的数据
  • 内存没有被读程序锁定

如果同时满足上述条件,写入函数首先锁定内存,然后从写进程的地址空间中复制数据到内存。否则,写入进程就休眠在 VFS 索引节点的等待队列中,接下来,内核将调用调度程序,而调度程序会选择其他进程运行。写入进程实际处于可中断的等待状态,当内存中有足够的空间可以容纳写入数据,或内存被解锁时,读取进程会唤醒写入进程,这时,写入进程将接收到信号。当数据写入内存之后,内存被解锁,而所有休眠在索引节点的读取进程会被唤醒。

管道的读取过程和写入过程类似。但是,进程可以在没有数据或内存被锁定时立即返回错误信息,而不是阻塞该进程,这依赖于文件或管道的打开模式。反之,进程可以休眠在索引节点的等待队列中等待写入进程写入数据。当所有的进程完成了管道操作之后,管道的索引节点被丢弃,而共享数据页也被释放。

管道的种类

  1. 普通管道:有两种限制,一是只能单向传输,二是只能在父子或兄弟进程间进行通信

  2. 半雙工管道

    只能在父子或兄弟进程间使用,可以双向传输

    shell中通過|表示管道,左邊的輸出作為右邊的輸入。

    進程創建管道時,需要創建兩個文件描述符來操作管道,一個讀,一個寫。兩個通信的進程中的讀與寫的描述符相對應。在進程A中設置為讀的描述符,在B中設置為寫。

    pipe()函數

    #include <unistd.h>
    int pipe(int filedes[2]);
    

    filedes是一個文件描述符的數組,第1個是讀,第2個是寫。

    pipe寫入數據時,寫入的數據小於128K時是非原子的。當大於128K時,緩衝區的數據會被連續地寫入管道,之後阻塞等待讀進程將所有的數據讀完。

  3. 命名管道FIFO

    文件系統中FIFO以設備特殊文件的形式存在,它在文件系统中有对应的路径,当一个进程以读的方式打开该文件,另一个进程以写的方式打开该文件,那么内核就会在这两个进程间建立管道。

    不同的進程可以通過FIFO共享數據

    • 創建FIFO

      shell中:mkfifo fifo_name

      C語言:

      #include <sys/stat.h>
      int mkfifo(const char *pathname, mode_t mode);
      
    • FIFO默認狀態下總是處於阻塞狀態,必須使用open()函數來顯式地建立到管道的連接,並且使用O_NONBLOCK標誌

消息隊列

消息隊列時內核空間中的內部鏈錶,通過內核在各個進程間傳遞內容。消息順序地發送到消息隊列中,並以幾種不同的方式從隊列中獲取,每個隊列通過IPC標識符唯一地標識,每個消息隊列中的消息,又構成一個獨立的鏈錶。

每个消息队列都有一个队列头,用结构struct msg_queue来描述。队列头中包含了该消息队列的大量信息,包括消息队列键值、用户ID、组ID、消息队列中消息数目等等,甚至记录了最近对消息队列读写进程的ID。读者可以访问这些信息,也可以设置其中的某些信息。

  • 消息緩衝區結構

    #include <linux/msg.h>
    struct msgmbuf {
        long mtype; //消息類型,用整數表示,可以為某類消息設定一個類型,以區分接收到的不同的消息
        char mtext[1]; //消息數據,長度不一定為1
    }
    

    对于发送消息来说,首先预置一个msgbuf缓冲区并写入消息类型和内容,调用相应的发送函数即可;对读取消息来说,首先分配这样一个msgbuf缓冲区,然后把消息读入该缓冲区即可。

    消息總的大小不能超過8192字節。

  • ipc_perm

    內核將IPC對象的許可權限信息放在ipc_perm類型的結構中。

    struct ipc_perm {
        key_t key; //用於區分消息隊列
        uid_t uid; //用戶的UID
        gid_t gid; //用戶組的id
        uid_t cuid; //建立者的UID
        gid_t cgid;
        unsigned short mode; //讀寫控制權限
        unsigned short seq; //序列號
    };
    
  • msqid_ds

    消息队列的信息基本上都保存在消息队列头中,因此,可以分配一个类似于消息队列头的结构(struct msqid_ds),来返回消息队列的属性;同样可以设置该数据结构。

    每個msqid_ds代表一個系統消息隊列。系統通過struct list_head q_messages來管理消息隊列,一個系統中最優有128個消息隊列。

    struct msqid_ds {
        struct ipc_perm msg_perm;
        struct msg *msg_first;      /* first message on queue,unused  */
        struct msg *msg_last;       /* last message in queue,unused */
        __kernel_time_t msg_stime;  /* last msgsnd time */
        __kernel_time_t msg_rtime;  /* last msgrcv time */
        __kernel_time_t msg_ctime;  /* last change time */
        unsigned long  msg_lcbytes; /* Reuse junk fields for 32 bit */
        unsigned long  msg_lqbytes; /* ditto */
        unsigned short msg_cbytes;  /* current number of bytes on queue */
        unsigned short msg_qnum;    /* number of messages in queue */
        unsigned short msg_qbytes;  /* max number of bytes on queue */
        __kernel_ipc_pid_t msg_lspid;   /* pid of last msgsnd */
        __kernel_ipc_pid_t msg_lrpid;   /* last receive pid */
    };
    

    消息隊列便通過msg_first和msg_lasr指針來鏈接頭和尾的消息體,消息體定義如下:

    /* one msg structure for each message */
    struct msg {
    	struct msg *msg_next;   /* next message on queue */
    	long  msg_type;          
    	char *msg_spot;         /* message text address */
    	time_t msg_stime;       /* msgsnd time */
    	short msg_ts;           /* message text size */
    };
    
  • 內核中的消息隊列的關係

  • 鍵值構建ftok()函數

    由於共享內存、消息隊列、信號量都是通過中間介質來進行通信的,想要唯一一個介質進程通信,需要指定一個id。ftok()函數用於產生這種id。

    將路徑名和項目的標識符轉變為一個系統V的IPC鍵值

    #include <sys/ipc.h>
    key_t ftok(const char* pathname, int proj_id);
    

    pathname是存在且可訪問的文件名,proj_id是隨便指定的一個數,1~255。

    ftok()的返回值是根據pathname對應的文件節點信息和proj_id生成的。文件節點結構為

    //函数:int stat( const char *file_name, struct stat *buf )
    //函数说明:通过文件名filename,获取文件信息,并保存在buf所指的结构体stat中。
    //返回值:成功执行返回0,失败返回-1,错误代码存于errno
    //struct stat结构体的定义如下:
    struct stat {
           unsigned long  st_dev;//文件的设备编号
           unsigned long  st_ino;//节点
           unsigned short st_mode; //文件的类型和存取的权限
           unsigned short st_nlink;//连到该文件的硬连接数目,刚建立的文件值为1
           unsigned short st_uid; //用户ID
           unsigned short st_gid; //组ID
           unsigned long st_rdev; 
           unsigned long  st_size;
           unsigned long st_blksize;
           unsigned long  st_blocks;
           unsigned long  st_atime;
           unsigned long st_atime_nsec;
           unsigned long  st_mtime;
           unsigned long st_mtime_nsec;
           unsigned long  st_ctime;
           unsigned long st_ctime_nsec;
           unsigned long  __unused4;
           unsigned long  __unused5;
    };
    

    ftok获取的键值是由ftok()函数的第二个参数的后8个bit,st_dev的后两位,st_ino的后四位构成的。

  • 獲得消息隊列id msgget()函數

    #include <sys/msg.h>
    #include <sys/ipc.h>
    int msgget(key_t key, int msgflag);
    

    成功調用返回消息隊列ID

    key即為ftok()創建的key

    msgflag:

    • IPC_CREAT:如果在內核中不存在該隊列,則創建它
    • IPC_EXCL:和IPC_CREAT一起使用時,如果隊列存在就出錯。為了保證沒有一個現存的隊列為了訪問而被打開。
  • 發送消息msgsend()函數

    int msgsend(int msqid, const void *msgp, size_t msgsz, int msgflg);

    msqid:消息隊列id

    msgp:指向一個消息緩衝區msgmbuf

    msgz:消息的大小,單位字節,不包括4字節的消息類型

    msgflg:指定設置為IPC_NOWAIT,如果消息隊列已滿就不繼續寫消息。沒有設置則進程阻塞,直到可以繼續寫消息。

  • 接受消息msgrcv()函數

    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz,long msgtyp, int msgflg);

    msgtyp表示要從隊列獲取的消息類型,內核將查找隊列中第一個到達的匹配類型的消息。如果傳0表示無論類型,接收最老的消息。

  • 消息控制msgctl()函數

    int msgctl(int msqid, int cmd, struct msqid_ds* buf);

    msgctl()函數向內核發送一個cmd命令

    • IPC_STAT:獲取隊列的msqid_ds結構放置于buf中
    • IPC_SET:設置隊列的msqid_ds結構的ipc_perm成員值,值從buf中獲得。
    • IPC_RMID:內核刪除隊列。
  1. 消息隊列

    消息隊列時內核空間中的內部鏈錶,通過內核在各個進程間傳遞內容。消息順序地發送到消息隊列中,並以幾種不同的方式從隊列中獲取,每個隊列通過IPC標識符唯一地標識,每個消息隊列中的消息,又構成一個獨立的鏈錶。

    每个消息队列都有一个队列头,用结构struct msg_queue来描述。队列头中包含了该消息队列的大量信息,包括消息队列键值、用户ID、组ID、消息队列中消息数目等等,甚至记录了最近对消息队列读写进程的ID。读者可以访问这些信息,也可以设置其中的某些信息。

    • 消息緩衝區結構

      #include <linux/msg.h>
      struct msgmbuf {
          long mtype; //消息類型,用整數表示,可以為某類消息設定一個類型,以區分接收到的不同的消息
          char mtext[1]; //消息數據,長度不一定為1
      }
      

      对于发送消息来说,首先预置一个msgbuf缓冲区并写入消息类型和内容,调用相应的发送函数即可;对读取消息来说,首先分配这样一个msgbuf缓冲区,然后把消息读入该缓冲区即可。

      消息總的大小不能超過8192字節。

    • ipc_perm

      內核將IPC對象的許可權限信息放在ipc_perm類型的結構中。

      struct ipc_perm {
          key_t key; //用於區分消息隊列
          uid_t uid; //用戶的UID
          gid_t gid; //用戶組的id
          uid_t cuid; //建立者的UID
          gid_t cgid;
          unsigned short mode; //讀寫控制權限
          unsigned short seq; //序列號
      };
      
    • msqid_ds

      消息队列的信息基本上都保存在消息队列头中,因此,可以分配一个类似于消息队列头的结构(struct msqid_ds),来返回消息队列的属性;同样可以设置该数据结构。

      每個msqid_ds代表一個系統消息隊列。系統通過struct list_head q_messages來管理消息隊列,一個系統中最優有128個消息隊列。

      struct msqid_ds {
          struct ipc_perm msg_perm;
          struct msg *msg_first;      /* first message on queue,unused  */
          struct msg *msg_last;       /* last message in queue,unused */
          __kernel_time_t msg_stime;  /* last msgsnd time */
          __kernel_time_t msg_rtime;  /* last msgrcv time */
          __kernel_time_t msg_ctime;  /* last change time */
          unsigned long  msg_lcbytes; /* Reuse junk fields for 32 bit */
          unsigned long  msg_lqbytes; /* ditto */
          unsigned short msg_cbytes;  /* current number of bytes on queue */
          unsigned short msg_qnum;    /* number of messages in queue */
          unsigned short msg_qbytes;  /* max number of bytes on queue */
          __kernel_ipc_pid_t msg_lspid;   /* pid of last msgsnd */
          __kernel_ipc_pid_t msg_lrpid;   /* last receive pid */
      };
      

      消息隊列便通過msg_first和msg_lasr指針來鏈接頭和尾的消息體,消息體定義如下:

      /* one msg structure for each message */
      struct msg {
      	struct msg *msg_next;   /* next message on queue */
      	long  msg_type;          
      	char *msg_spot;         /* message text address */
      	time_t msg_stime;       /* msgsnd time */
      	short msg_ts;           /* message text size */
      };
      
    • 內核中的消息隊列的關係

    • 鍵值構建ftok()函數

      由於共享內存、消息隊列、信號量都是通過中間介質來進行通信的,想要唯一一個介質進程通信,需要指定一個id。ftok()函數用於產生這種id。

      將路徑名和項目的標識符轉變為一個系統V的IPC鍵值

      #include <sys/ipc.h>
      key_t ftok(const char* pathname, int proj_id);
      

      pathname是存在且可訪問的文件名,proj_id是隨便指定的一個數,1~255。

      ftok()的返回值是根據pathname對應的文件節點信息和proj_id生成的。文件節點結構為

      //函数:int stat( const char *file_name, struct stat *buf )
      //函数说明:通过文件名filename,获取文件信息,并保存在buf所指的结构体stat中。
      //返回值:成功执行返回0,失败返回-1,错误代码存于errno
      //struct stat结构体的定义如下:
      struct stat {
             unsigned long  st_dev;//文件的设备编号
             unsigned long  st_ino;//节点
             unsigned short st_mode; //文件的类型和存取的权限
             unsigned short st_nlink;//连到该文件的硬连接数目,刚建立的文件值为1
             unsigned short st_uid; //用户ID
             unsigned short st_gid; //组ID
             unsigned long st_rdev; 
             unsigned long  st_size;
             unsigned long st_blksize;
             unsigned long  st_blocks;
             unsigned long  st_atime;
             unsigned long st_atime_nsec;
             unsigned long  st_mtime;
             unsigned long st_mtime_nsec;
             unsigned long  st_ctime;
             unsigned long st_ctime_nsec;
             unsigned long  __unused4;
             unsigned long  __unused5;
      };
      

      ftok获取的键值是由ftok()函数的第二个参数的后8个bit,st_dev的后两位,st_ino的后四位构成的。

    • 獲得消息隊列id msgget()函數

      #include <sys/msg.h>
      #include <sys/ipc.h>
      int msgget(key_t key, int msgflag);
      

      成功調用返回消息隊列ID

      key即為ftok()創建的key

      msgflag:

      • IPC_CREAT:如果在內核中不存在該隊列,則創建它
      • IPC_EXCL:和IPC_CREAT一起使用時,如果隊列存在就出錯。為了保證沒有一個現存的隊列為了訪問而被打開。
    • 發送消息msgsend()函數

      int msgsend(int msqid, const void *msgp, size_t msgsz, int msgflg);

      msqid:消息隊列id

      msgp:指向一個消息緩衝區msgmbuf

      msgz:消息的大小,單位字節,不包括4字節的消息類型

      msgflg:指定設置為IPC_NOWAIT,如果消息隊列已滿就不繼續寫消息。沒有設置則進程阻塞,直到可以繼續寫消息。

    • 接受消息msgrcv()函數

      ssize_t msgrcv(int msqid, void *msgp, size_t msgsz,long msgtyp, int msgflg);

      msgtyp表示要從隊列獲取的消息類型,內核將查找隊列中第一個到達的匹配類型的消息。如果傳0表示無論類型,接收最老的消息。

    • 消息控制msgctl()函數

      int msgctl(int msqid, int cmd, struct msqid_ds* buf);

      msgctl()函數向內核發送一個cmd命令

      • IPC_STAT:獲取隊列的msqid_ds結構放置于buf中
      • IPC_SET:設置隊列的msqid_ds結構的ipc_perm成員值,值從buf中獲得。
      • IPC_RMID:內核刪除隊列。

信號量

信號量是一種計數器,用來控制多個進程共享的資源的訪問。常常用來預防死鎖。信号量是一个特殊的变量,程序对其访问都是原子操作,且只允许对它进行等待(即P(信号变量))和发送(即V(信号变量))信息操作。

數據結構

union semun {
    int val;
    struct semid_ds* buf;
    unsigned short* array;
    struct seminfo* __buf;
}

semget函数

创建一个新信号量或取得一个已有信号量

int semget(key_t key, int num_sems, int sem_flags)

  • 第一个参数key是整数值(唯一非零),不相关的进程可以通过它访问一个信号量,它代表程序可能要使用的某个资源,程序对所有信号量的访问都是间接的,程序先通过调用semget函数并提供一个键,再由系统生成一个相应的信号标识符(semget函数的返回值),只有semget函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回的信号量标识符。如果多个程序使用相同的key值,key将负责协调工作。
  • 第二个参数num_sems指定需要的信号量数目
  • 第三个参数sem_flags是一组标志,当想要当信号量不存在时创建一个新的信号量,可以和值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,即使给出的键是一个已有信号量的键,也不会产生错误。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。

semget函数成功返回一个相应信号标识符(非零),失败返回-1.

semop函数

改变信号量的值,原型为

int semop(int sem_id, struct sembuf* sem_opa, size_t num_sem_ops);

sem_id是由semget返回的信号量标识符,sembuf结构的定义为

struct sembuf{  
    short sem_num;//除非使用一组信号量,否则它为0  
    short sem_op;//信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,  
                    //一个是+1,即V(发送信号)操作。  
    short sem_flg;//通常为SEM_UNDO,使操作系统跟踪信号,  
                    //并在进程没有释放该信号量而终止时,操作系统释放信号量  
};  

共享內存

共享內存時在多個進程之間共享內存區域的一種進程間的通信方式,它是在多個進程之間對內存段進行映射的方式實現內存共享的。這是IPC最快捷的方式,因為共享內存方式的通信沒有中間過程,不需要像其他方式一樣將消息經過中間機制的轉換。

共享內存時直接將某段內存進行映射,多個進程共享的內存是同一塊物理空間,但是邏輯空間的地址不同。

  • 創建共享內存函數shmget()

    #include <sys/ipc.h>
    #include <sys/shm.h>
    int shmget(key_t key, size_t size, int shmflg);
    

    shmget()通過第一個參數比較內核中現有的共享內存的關鍵值,比較之後,打開和訪問操作都依賴於shmflg參數的內容。參數的可選項IPC_CREAT和IPC_EXCL和前面的信號量和消息隊列的參數都一樣。

    調用成功後返回新創建的內存段的段標識符。

  • 獲得共享內存地址函數shmat()

    利用創建好的共享內存標識符,可以將進程與共享內存綁定。

  • 進程與共享內存解綁shmdt()

    但是共享內存解綁後不會立刻變為普通內存,只有當與共享內存連接的進程數量為0時,共享內存才會刪除。

  • 共享內存控制函數shmctl()

    #include <sys/ipc.h>
    #include <sys/shm.h>
    int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    

    PC_RMID:删除。(常用 )

    IPC_SET:设置 shmid_ds 参数,相当于把共享内存原来的属性值替换为 buf 里的属性值。

    IPC_STAT:保存 shmid_ds 参数,把共享内存原来的属性值备份到 buf 里。

    SHM_LOCK:锁定共享内存段( 超级用户 )。

    SHM_UNLOCK:解锁共享内存段。

    SHM_LOCK 用于锁定内存,禁止内存交换。并不代表共享内存被锁定后禁止其它进程访问。其真正的意义是:被锁定的内存不允许被交换到虚拟内存中。这样做的优势在于让共享内存一直处于内存中,从而提高程序性能。

信號

信號機制用於在一個或多個進程之間傳遞異步信號。

查看所有信號kill -l

進程可以屏蔽大多數信號,除了使進程暫停的SIGSTOP和使進程退出的SIGKILL

進程接收到信號後通常會執行操作系統默認的行為,如果用戶定義了進程的行為則執行用戶設定的行為。

現介紹幾種常用信號

  • SIGABRT:調用abort()函數產生此信號,進程異常終止。
  • SIGALRM:超過用alarm()函數設置的時間時產生此信號。
  • SIGCHLD:當一個進程終止或停止時,此信號被送給父進程,通常與wait()函數一起使用。
  • SIGCONT:此信號送給需要繼續運行的進程,若接收到此信號的進處於進程,則操作系統默認使該進程繼續運行。
  • SIGFPE:表示一個算數運算異常。
  • SIGIO:發生了一個異步IO事件。
  • SIGPIPE:如果在讀進程時已終止寫管道,則產生此進程。
  • SIGQUIT:用戶在中斷按下退出鍵(如Ctrl+C)時,產生此信號。
  • SIGTERM: kill命令發送的系統默認終止信號。

常用信號處理函數

  1. 信號截取函數signal()

    signal()函數用於截取系統的信號,對此信號掛接用戶自己的處理程序

    #include <signal.h>
    typedef void (*sighandler_t)(int);
    sighandler_t signal(int signum, sighandler_t handler);
    

    可以看出signal()接收一個信號參數和一個函數指針參數,返回一個沒有返回值的函數指針。

  2. 向進程發送信號的kill()和raise()

    #include <signal.h>
    int kill(pid_t pid, int sig);
    int raise(int sig);
    

    kill向進程id為pid的進程發送信號,pid=0時,向所有進程發送信號

    raise向當前進程發送信號。


Linux下的線程

Linux下的多線程遵循POSIX標準,稱為pthread。編寫Linux下的多線程需要包含頭文件pthread.h,生成可執行文件時需要鏈接庫libptherad.a或者libpthread.so。

  1. 線程創建函數pthread_create()

    int pthread_create(pthread_t* thread, pthread_attr* attr, void* (*start_routine)(void*),void* arg);
    

    thread為進程標識符,attr表示屬性,進程用來設置線程的優先級。start_routine為分配進程需要執行的函數程序,


References

  1. Linux进程间的通信方式和原理
  2. Linux网络编程
我愿潇洒如鹰,远离地上宿命
原文地址:https://www.cnblogs.com/lunar-ubuntu/p/12910140.html