搜尋
首頁常見問題進程間的五種通訊方式是什麼
進程間的五種通訊方式是什麼Dec 07, 2020 pm 01:51 PM
行程通訊方式

進程間的五種通訊方式:1、管道,速度慢,容量有限,只有父子進程能通訊;2、FIFO,任何進程間都能通訊,但速度慢;3、訊息佇列,可以實現訊息的隨機查詢,容量受到系統限制;4、信號量,不能傳遞複雜訊息,只能用來同步;5、共享記憶體區,指兩個或多個進程共享一個給定的儲存區。

進程間的五種通訊方式是什麼

本教學操作環境:windows7系統、Dell G3電腦。

進程間的五種通訊方式:

#一、管道

##管道,通常指無名管道,是UNIX 系統IPC最古老的形式。

1、特點:

  • 它是半雙工的(即資料只能在一個方向上流動),具有固定的讀端和寫端。

  • 它只能用於具有親緣關係的進程之間的溝通(也是父子進程或兄弟進程之間)。

  • 它可以看成是一種特殊的文件,對於它的讀寫也可以使用普通的read、write 等函數。但是它不是普通的文件,並不屬於其他任何文件系統,並且只存在於記憶體中。

2、原型:
1 #include <unistd.h>
2 int pipe(int fd[2]);    // 返回值:若成功返回0,失败返回-1</unistd.h>

當一個管道建立時,它會建立兩個檔案描述符:

fd[0 ]為讀取而打開,fd[1]為寫而打開。如下圖:

要關閉管道只需將這兩個檔案描述子關閉即可。

3、範例

單一行程中的管道幾乎沒有任何用處。所以,通常會呼叫 pipe 的程序接著呼叫 fork,這樣就建立了父進程與子程序之間的 IPC 通道。如下圖所示:

進程間的五種通訊方式是什麼

若要資料流從父行程流向子程序,則關閉父程序的讀端(

fd[0])與子程序的寫端(fd[1]);反之,則可以使資料流從子程序流向父程序。

 1 #include<stdio.h>
 2 #include<unistd.h>
 3 
 4 int main()
 5 {
 6     int fd[2];  // 两个文件描述符
 7     pid_t pid;
 8     char buff[20];
 9 
10     if(pipe(fd)  0)  // 父进程
16     {
17         close(fd[0]); // 关闭读端
18         write(fd[1], "hello world\n", 12);
19     }
20     else
21     {
22         close(fd[1]); // 关闭写端
23         read(fd[0], buff, 20);
24         printf("%s", buff);
25     }
26 
27     return 0;
28 }</unistd.h></stdio.h>

二、FIFO

FIFO,也稱為命名管道,它是一種檔案類型。

1、特點

  1. FIFO可以在無關的進程之間交換數據,與無名管道不同。

  2. FIFO有路徑名與之相關聯,它以特殊設備檔案形式存在於檔案系統中。

2、原型

1 #include <sys>
2 // 返回值:成功返回0,出错返回-1
3 int mkfifo(const char *pathname, mode_t mode);</sys>

其中的 mode 參數與

open函數中的 mode 相同。一旦建立了一個 FIFO,就可以用一般的檔案I/O函數來操作它。

當open 一個FIFO時,是否設定非阻塞標誌(

O_NONBLOCK)的差異:

  • 若沒有指定

    O_NONBLOCK(預設),只讀open 要阻塞到某個其他程序為寫而開啟此FIFO。類似的,只寫 open 要阻塞到某個其他行程為讀取而開啟它。

  • 若指定了

    O_NONBLOCK,則只讀 open 立即返回。而只寫 open 將出錯傳回 -1 如果沒有進程已經為讀取而開啟該 FIFO,其errno置ENXIO。

3、範例

FIFO的通訊方式類似於在流程中使用檔案來傳輸數據,只不過FIFO類型檔案同時具有管道的特性。在數據讀出時,FIFO管道中同時清除數據,並且「先進先出」。下面的範例示範了使用FIFO 進行IPC 的過程:

write_fifo.c

 1 #include<stdio.h>
 2 #include<stdlib.h>   // exit
 3 #include<fcntl.h>    // O_WRONLY
 4 #include<sys>
 5 #include<time.h>     // time
 6 
 7 int main()
 8 {
 9     int fd;
10     int n, i;
11     char buf[1024];
12     time_t tp;
13 
14     printf("I am %d process.\n", getpid()); // 说明进程ID
15     
16     if((fd = open("fifo1", O_WRONLY)) read_fifo.c<p></p>
<pre class="brush:php;toolbar:false"> 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<errno.h>
 4 #include<fcntl.h>
 5 #include<sys>
 6 
 7 int main()
 8 {
 9     int fd;
10     int len;
11     char buf[1024];
12 
13     if(mkfifo("fifo1", 0666)  0) // 读取FIFO管道
23         printf("Read message: %s", buf);
24 
25     close(fd);  // 关闭FIFO文件
26     return 0;
27 }</sys></fcntl.h></errno.h></stdlib.h></stdio.h>
在兩個終端裡用gcc 分別編譯運行上面兩個文件,可以看到輸出結果如下:

 1 [cheesezh@localhost]$ ./write_fifo 
 2 I am 5954 process.
 3 Send message: Process 5954's time is Mon Apr 20 12:37:28 2015
 4 Send message: Process 5954's time is Mon Apr 20 12:37:29 2015
 5 Send message: Process 5954's time is Mon Apr 20 12:37:30 2015
 6 Send message: Process 5954's time is Mon Apr 20 12:37:31 2015
 7 Send message: Process 5954's time is Mon Apr 20 12:37:32 2015
 8 Send message: Process 5954's time is Mon Apr 20 12:37:33 2015
 9 Send message: Process 5954's time is Mon Apr 20 12:37:34 2015
10 Send message: Process 5954's time is Mon Apr 20 12:37:35 2015
11 Send message: Process 5954's time is Mon Apr 20 12:37:36 2015
12 Send message: Process 5954's time is Mon Apr 20 12:37:37 2015
 1 [cheesezh@localhost]$ ./read_fifo 
 2 Read message: Process 5954's time is Mon Apr 20 12:37:28 2015
 3 Read message: Process 5954's time is Mon Apr 20 12:37:29 2015
 4 Read message: Process 5954's time is Mon Apr 20 12:37:30 2015
 5 Read message: Process 5954's time is Mon Apr 20 12:37:31 2015
 6 Read message: Process 5954's time is Mon Apr 20 12:37:32 2015
 7 Read message: Process 5954's time is Mon Apr 20 12:37:33 2015
 8 Read message: Process 5954's time is Mon Apr 20 12:37:34 2015
 9 Read message: Process 5954's time is Mon Apr 20 12:37:35 2015
10 Read message: Process 5954's time is Mon Apr 20 12:37:36 2015
11 Read message: Process 5954's time is Mon Apr 20 12:37:37 2015
上述例子可以擴展成客戶進程—伺服器進程通訊的實例,

write_fifo的作用類似於客戶端,可以開啟多個客戶端向一個伺服器發送請求訊息,read_fifo類似於伺服器,它適時監控FIFO的讀端,當有資料時,讀出並進行處理,但是有一個關鍵的問題是,每個客戶端必須預先知道伺服器提供的FIFO接口,下圖顯示了這種安排:

#三、訊息佇列##訊息佇列,是訊息的連結表,存放在核心中。一個訊息佇列由一個識別碼(即佇列ID)來識別。

1、特點

    訊息佇列是面向記錄的,其中的訊息具有特定的格式以及特定的優先權。
  1. 訊息佇列獨立於傳送與接收程序。進程終止時,訊息佇列及其內容並不會被刪除。
  2. 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。

2、原型

1 #include <sys>
2 // 创建或打开消息队列:成功返回队列ID,失败返回-1
3 int msgget(key_t key, int flag);
4 // 添加消息:成功返回0,失败返回-1
5 int msgsnd(int msqid, const void *ptr, size_t size, int flag);
6 // 读取消息:成功返回消息数据的长度,失败返回-1
7 int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
8 // 控制消息队列:成功返回0,失败返回-1
9 int msgctl(int msqid, int cmd, struct msqid_ds *buf);</sys>

在以下两种情况下,msgget将创建一个新的消息队列:

  • 如果没有与键值key相对应的消息队列,并且flag中包含了IPC_CREAT标志位。
  • key参数为IPC_PRIVATE

函数msgrcv在读取消息队列时,type参数有下面几种情况:

  • type == 0,返回队列中的第一个消息;
  • type > 0,返回队列中消息类型为 type 的第一个消息;
  • type ,返回队列中消息类型值小于或等于 type 绝对值的消息,如果有多个,则取类型值最小的消息。

可以看出,type值非 0 时用于以非先进先出次序读消息。也可以把 type 看做优先级的权值。(其他的参数解释,请自行Google之)

3、例子

下面写了一个简单的使用消息队列进行IPC的例子,服务端程序一直在等待特定类型的消息,当收到该类型的消息以后,发送另一种特定类型的消息作为反馈,客户端读取该反馈并打印出来。

msg_server.c

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <sys>
 4 
 5 // 用于创建一个唯一的key
 6 #define MSG_FILE "/etc/passwd"
 7 
 8 // 消息结构
 9 struct msg_form {
10     long mtype;
11     char mtext[256];
12 };
13 
14 int main()
15 {
16     int msqid;
17     key_t key;
18     struct msg_form msg;
19     
20     // 获取key值
21     if((key = ftok(MSG_FILE,'z')) <p>msg_client.c</p>
<pre class="brush:php;toolbar:false"> 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <sys>
 4 
 5 // 用于创建一个唯一的key
 6 #define MSG_FILE "/etc/passwd"
 7 
 8 // 消息结构
 9 struct msg_form {
10     long mtype;
11     char mtext[256];
12 };
13 
14 int main()
15 {
16     int msqid;
17     key_t key;
18     struct msg_form msg;
19 
20     // 获取key值
21     if ((key = ftok(MSG_FILE, 'z')) <h2 id="strong-四-信号量-strong"><strong>四、信号量</strong></h2>
<p>信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。</p>
<h3 id="特点">1、特点</h3>
<ol>
<li><p>信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。</p></li>
<li><p>信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。</p></li>
<li><p>每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。</p></li>
<li><p>支持信号量组。</p></li>
</ol>
<h3 id="原型">2、原型</h3>
<p>最简单的信号量是只能取 0 和 1 的变量,这也是信号量最常见的一种形式,叫做二值信号量(Binary Semaphore)。而可以取多个正整数的信号量被称为通用信号量。</p>
<p>Linux 下的信号量函数都是在通用的信号量数组上进行操作,而不是在一个单一的二值信号量上进行操作。</p>
<pre class="brush:php;toolbar:false">1 #include <sys>
2 // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
3 int semget(key_t key, int num_sems, int sem_flags);
4 // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
5 int semop(int semid, struct sembuf semoparray[], size_t numops);  
6 // 控制信号量的相关信息
7 int semctl(int semid, int sem_num, int cmd, ...);</sys>

semget创建新的信号量集合时,必须指定集合中信号量的个数(即num_sems),通常为1; 如果是引用一个现有的集合,则将num_sems指定为 0 。

semop函数中,sembuf结构的定义如下:

1 struct sembuf 
2 {
3     short sem_num; // 信号量组中对应的序号,0~sem_nums-1
4     short sem_op;  // 信号量值在一次操作中的改变量
5     short sem_flg; // IPC_NOWAIT, SEM_UNDO
6 }

其中 sem_op 是一次操作中的信号量的改变量:

  • sem_op > 0,表示进程释放相应的资源数,将 sem_op 的值加到信号量的值上。如果有进程正在休眠等待此信号量,则换行它们。

  • sem_op ,请求 sem_op 的绝对值的资源。

    • 如果相应的资源数可以满足请求,则将该信号量的值减去sem_op的绝对值,函数成功返回。
    • 当相应的资源数不能满足请求时,这个操作与sem_flg有关。
      • sem_flg 指定IPC_NOWAIT,则semop函数出错返回EAGAIN
      • sem_flg 没有指定IPC_NOWAIT,则将该信号量的semncnt值加1,然后进程挂起直到下述情况发生:
        1. 当相应的资源数可以满足请求,此信号量的semncnt值减1,该信号量的值减去sem_op的绝对值。成功返回;
        2. 此信号量被删除,函数smeop出错返回EIDRM;
        3. 进程捕捉到信号,并从信号处理函数返回,此情况下将此信号量的semncnt值减1,函数semop出错返回EINTR
  • sem_op == 0,进程阻塞直到信号量的相应值为0:

    • 当信号量已经为0,函数立即返回。
    • 如果信号量的值不为0,则依据sem_flg决定函数动作:
      • sem_flg指定IPC_NOWAIT,则出错返回EAGAIN
      • sem_flg没有指定IPC_NOWAIT,则将该信号量的semncnt值加1,然后进程挂起直到下述情况发生:
        1. 信号量值为0,将信号量的semzcnt的值减1,函数semop成功返回;
        2. 此信号量被删除,函数smeop出错返回EIDRM;
        3. 进程捕捉到信号,并从信号处理函数返回,在此情况将此信号量的semncnt值减1,函数semop出错返回EINTR

semctl函数中的命令有多种,这里就说两个常用的:

  • SETVAL:用于初始化信号量为一个已知的值。所需要的值作为联合semun的val成员来传递。在信号量第一次使用之前需要设置信号量。
  • IPC_RMID:删除一个信号量集合。如果不删除信号量,它将继续在系统中存在,即使程序已经退出,它可能在你下次运行此程序时引发问题,而且信号量是一种有限的资源。

3、例子

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys>
  4 
  5 // 联合体,用于semctl初始化
  6 union semun
  7 {
  8     int              val; /*for SETVAL*/
  9     struct semid_ds *buf;
 10     unsigned short  *array;
 11 };
 12 
 13 // 初始化信号量
 14 int init_sem(int sem_id, int value)
 15 {
 16     union semun tmp;
 17     tmp.val = value;
 18     if(semctl(sem_id, 0, SETVAL, tmp) == -1)
 19     {
 20         perror("Init Semaphore Error");
 21         return -1;
 22     }
 23     return 0;
 24 }
 25 
 26 // P操作:
 27 //    若信号量值为1,获取资源并将信号量值-1 
 28 //    若信号量值为0,进程挂起等待
 29 int sem_p(int sem_id)
 30 {
 31     struct sembuf sbuf;
 32     sbuf.sem_num = 0; /*序号*/
 33     sbuf.sem_op = -1; /*P操作*/
 34     sbuf.sem_flg = SEM_UNDO;
 35 
 36     if(semop(sem_id, &sbuf, 1) == -1)
 37     {
 38         perror("P operation Error");
 39         return -1;
 40     }
 41     return 0;
 42 }
 43 
 44 // V操作:
 45 //    释放资源并将信号量值+1
 46 //    如果有进程正在挂起等待,则唤醒它们
 47 int sem_v(int sem_id)
 48 {
 49     struct sembuf sbuf;
 50     sbuf.sem_num = 0; /*序号*/
 51     sbuf.sem_op = 1;  /*V操作*/
 52     sbuf.sem_flg = SEM_UNDO;
 53 
 54     if(semop(sem_id, &sbuf, 1) == -1)
 55     {
 56         perror("V operation Error");
 57         return -1;
 58     }
 59     return 0;
 60 }
 61 
 62 // 删除信号量集
 63 int del_sem(int sem_id)
 64 {
 65     union semun tmp;
 66     if(semctl(sem_id, 0, IPC_RMID, tmp) == -1)
 67     {
 68         perror("Delete Semaphore Error");
 69         return -1;
 70     }
 71     return 0;
 72 }
 73 
 74 
 75 int main()
 76 {
 77     int sem_id;  // 信号量集ID
 78     key_t key;  
 79     pid_t pid;
 80 
 81     // 获取key值
 82     if((key = ftok(".", 'z')) <p>上面的例子如果不加信号量,则父进程会先执行完毕。这里加了信号量让父进程等待子进程执行完以后再执行。</p>
<h2 id="strong-五-共享内存-strong"><strong>五、共享内存</strong></h2>
<p>共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。</p>
<h3 id="特点">1、特点</h3>
<ol>
<li><p>共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。</p></li>
<li><p>因为多个进程可以同时操作,所以需要进行同步。</p></li>
<li><p>信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。</p></li>
</ol>
<h3 id="原型">2、原型</h3>
<pre class="brush:php;toolbar:false">1 #include <sys>
2 // 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
3 int shmget(key_t key, size_t size, int flag);
4 // 连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1
5 void *shmat(int shm_id, const void *addr, int flag);
6 // 断开与共享内存的连接:成功返回0,失败返回-1
7 int shmdt(void *addr); 
8 // 控制共享内存的相关信息:成功返回0,失败返回-1
9 int shmctl(int shm_id, int cmd, struct shmid_ds *buf);</sys>

当用shmget函数创建一段共享内存时,必须指定其 size;而如果引用一个已存在的共享内存,则将 size 指定为0 。

当一段共享内存被创建以后,它并不能被任何进程访问。必须使用shmat函数连接该共享内存到当前进程的地址空间,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问。

shmdt函数是用来断开shmat建立的连接的。注意,这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已。

shmctl函数可以对共享内存执行多种操作,根据参数 cmd 执行相应的操作。常用的是IPC_RMID(从系统中删除该共享内存)。

3、例子

下面这个例子,使用了【共享内存+信号量+消息队列】的组合来实现服务器进程与客户进程间的通信。

  • 共享内存用来传递数据;
  • 信号量用来同步;
  • 消息队列用来 在客户端修改了共享内存后 通知服务器读取。

server.c

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys>  // shared memory
  4 #include<sys>  // semaphore
  5 #include<sys>  // message queue
  6 #include<string.h>   // memcpy
  7 
  8 // 消息队列结构
  9 struct msg_form {
 10     long mtype;
 11     char mtext;
 12 };
 13 
 14 // 联合体,用于semctl初始化
 15 union semun
 16 {
 17     int              val; /*for SETVAL*/
 18     struct semid_ds *buf;
 19     unsigned short  *array;
 20 };
 21 
 22 // 初始化信号量
 23 int init_sem(int sem_id, int value)
 24 {
 25     union semun tmp;
 26     tmp.val = value;
 27     if(semctl(sem_id, 0, SETVAL, tmp) == -1)
 28     {
 29         perror("Init Semaphore Error");
 30         return -1;
 31     }
 32     return 0;
 33 }
 34 
 35 // P操作:
 36 //  若信号量值为1,获取资源并将信号量值-1 
 37 //  若信号量值为0,进程挂起等待
 38 int sem_p(int sem_id)
 39 {
 40     struct sembuf sbuf;
 41     sbuf.sem_num = 0; /*序号*/
 42     sbuf.sem_op = -1; /*P操作*/
 43     sbuf.sem_flg = SEM_UNDO;
 44 
 45     if(semop(sem_id, &sbuf, 1) == -1)
 46     {
 47         perror("P operation Error");
 48         return -1;
 49     }
 50     return 0;
 51 }
 52 
 53 // V操作:
 54 //  释放资源并将信号量值+1
 55 //  如果有进程正在挂起等待,则唤醒它们
 56 int sem_v(int sem_id)
 57 {
 58     struct sembuf sbuf;
 59     sbuf.sem_num = 0; /*序号*/
 60     sbuf.sem_op = 1;  /*V操作*/
 61     sbuf.sem_flg = SEM_UNDO;
 62 
 63     if(semop(sem_id, &sbuf, 1) == -1)
 64     {
 65         perror("V operation Error");
 66         return -1;
 67     }
 68     return 0;
 69 }
 70 
 71 // 删除信号量集
 72 int del_sem(int sem_id)
 73 {
 74     union semun tmp;
 75     if(semctl(sem_id, 0, IPC_RMID, tmp) == -1)
 76     {
 77         perror("Delete Semaphore Error");
 78         return -1;
 79     }
 80     return 0;
 81 }
 82 
 83 // 创建一个信号量集
 84 int creat_sem(key_t key)
 85 {
 86     int sem_id;
 87     if((sem_id = semget(key, 1, IPC_CREAT|0666)) == -1)
 88     {
 89         perror("semget error");
 90         exit(-1);
 91     }
 92     init_sem(sem_id, 1);  /*初值设为1资源未占用*/
 93     return sem_id;
 94 }
 95 
 96 
 97 int main()
 98 {
 99     key_t key;
100     int shmid, semid, msqid;
101     char *shm;
102     char data[] = "this is server";
103     struct shmid_ds buf1;  /*用于删除共享内存*/
104     struct msqid_ds buf2;  /*用于删除消息队列*/
105     struct msg_form msg;  /*消息队列用于通知对方更新了共享内存*/
106 
107     // 获取key值
108     if((key = ftok(".", 'z')) <p>client.c</p>
<pre class="brush:php;toolbar:false">  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys>  // shared memory
  4 #include<sys>  // semaphore
  5 #include<sys>  // message queue
  6 #include<string.h>   // memcpy
  7 
  8 // 消息队列结构
  9 struct msg_form {
 10     long mtype;
 11     char mtext;
 12 };
 13 
 14 // 联合体,用于semctl初始化
 15 union semun
 16 {
 17     int              val; /*for SETVAL*/
 18     struct semid_ds *buf;
 19     unsigned short  *array;
 20 };
 21 
 22 // P操作:
 23 //  若信号量值为1,获取资源并将信号量值-1 
 24 //  若信号量值为0,进程挂起等待
 25 int sem_p(int sem_id)
 26 {
 27     struct sembuf sbuf;
 28     sbuf.sem_num = 0; /*序号*/
 29     sbuf.sem_op = -1; /*P操作*/
 30     sbuf.sem_flg = SEM_UNDO;
 31 
 32     if(semop(sem_id, &sbuf, 1) == -1)
 33     {
 34         perror("P operation Error");
 35         return -1;
 36     }
 37     return 0;
 38 }
 39 
 40 // V操作:
 41 //  释放资源并将信号量值+1
 42 //  如果有进程正在挂起等待,则唤醒它们
 43 int sem_v(int sem_id)
 44 {
 45     struct sembuf sbuf;
 46     sbuf.sem_num = 0; /*序号*/
 47     sbuf.sem_op = 1;  /*V操作*/
 48     sbuf.sem_flg = SEM_UNDO;
 49 
 50     if(semop(sem_id, &sbuf, 1) == -1)
 51     {
 52         perror("V operation Error");
 53         return -1;
 54     }
 55     return 0;
 56 }
 57 
 58 
 59 int main()
 60 {
 61     key_t key;
 62     int shmid, semid, msqid;
 63     char *shm;
 64     struct msg_form msg;
 65     int flag = 1; /*while循环条件*/
 66 
 67     // 获取key值
 68     if((key = ftok(".", 'z')) <p>注意:当<code>scanf()</code>输入字符或字符串时,缓冲区中遗留下了<code>\n</code>,所以每次输入操作后都需要清空标准输入的缓冲区。但是由于 gcc 编译器不支持<code>fflush(stdin)</code>(它只是标准C的扩展),所以我们使用了替代方案:</p>
<pre class="brush:php;toolbar:false">1 while((c=getchar())!='\n' && c!=EOF);

五种通讯方式总结

1.管道:速度慢,容量有限,只有父子进程能通讯    

2.FIFO:任何进程间都能通讯,但速度慢    

3.消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题    

4.信号量:不能传递复杂消息,只能用来同步    

5.共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存

相关免费学习推荐:php编程(视频)

以上是進程間的五種通訊方式是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
解释一下explorer.exe进程是什么解释一下explorer.exe进程是什么Feb 18, 2024 pm 12:11 PM

explorer.exe是什么进程在我们使用Windows操作系统的时候,经常会听到一个名词"explorer.exe".那么,你是否好奇这个进程到底是什么?在本文中,我们将详细解释explorer.exe是什么进程以及其功能和作用。首先,explorer.exe是Windows操作系统的一个关键进程,它负责管理和控制Windows资源管理器(Window

com surrogate是什么进程com surrogate是什么进程Sep 14, 2022 pm 02:56 PM

“com surrogate”是“C:\Windows\System32\dllhost.exe”的进程;出现该进程通常是“COM+”组件停止工作,这个进程占用高甚至直接未响应,这是由于电脑在加载文件图标的时候出现问题,导致电脑变的卡顿,可以在计算机属性设置中解决卡顿问题。

请问ccsvchst.exe是哪种进程?请问ccsvchst.exe是哪种进程?Feb 19, 2024 pm 11:33 PM

ccsvchst.exe是一种常见的进程文件,它是SymantecEndpointProtection(SEP)软件的一部分,而SEP则是一款由著名的网络安全公司Symantec开发的终端保护解决方案。作为该软件的一部分,ccsvchst.exe负责管理和监控SEP的相关进程。首先,我们来了解一下SymantecEndpointProtection(

如何正确杀死Linux中的僵尸进程如何正确杀死Linux中的僵尸进程Feb 19, 2024 am 10:40 AM

在Linux系统中,僵尸进程是已经终止但仍保留在系统中的特殊进程。虽然僵尸进程不会消耗太多资源,但如果数量过多,可能会导致系统资源耗尽。本文将介绍如何正确清除僵尸进程,以确保系统的正常运行。1Linux僵尸进程子进程完成任务后,如果父进程没有及时检查状态,子进程将成为僵尸进程。子进程在等待父进程确认,完成后系统才会回收。否则,僵尸进程会继续悬挂在系统中。要检查系统中是否存在僵尸进程,可通过运行命令top来查看所有正在运行的进程及可能存在的僵尸进程。‘top’命令的结果从上图可以看到Linux中进

如何在 Windows 11 中停止任务管理器进程更新并更方便地终止任务如何在 Windows 11 中停止任务管理器进程更新并更方便地终止任务Aug 20, 2023 am 11:05 AM

如何在Windows11和Windows10中暂停任务管理器进程更新按CTRL+窗口键+删除打开任务管理器。默认情况下,任务管理器将打开“进程”窗口。正如您在此处看到的,所有应用程序都在无休止地移动,当您想要选择它们时,可能很难将它们指向下方。因此,按CTRL并按住它,这将暂停任务管理器。您仍然可以选择应用程序,甚至可以向下滚动,但您必须始终按住CTRL按钮。

Linux如何杀掉僵尸进程Linux如何杀掉僵尸进程Feb 19, 2024 pm 04:24 PM

本文主要介绍Linux僵尸进程以及清理僵尸进程的方法。1、什么是僵尸进程?Linux中的僵尸进程(Zombieprocesses)有时也被称为失效或死亡进程。它们是已执行完毕的进程,但其条目并未从进程表中删除。1.1进程状态Linux会维护一个进程表,其中包含所有正在运行的进程及其状态。下面简要介绍一下各种进程状态:(1)Running(R):表示这些进程目前正在运行或可运行,用字母R表示。需要说明:进程是R状态,不代表正在运行,代表可被调度。换句话说,进程只有是R状态才可被调度,其他状态要先转

什么是程序运行时指令流的最小单位什么是程序运行时指令流的最小单位Aug 23, 2022 pm 02:16 PM

“线程”是程序运行时指令流的最小单位。进程是指一个具有一定独立功能的程序,而线程是进程的一部分,描述指令流执行状态;线程是进程中的指令执行流的最小单位,是CPU调度的基本单位。一个线程是一个任务(一个程序段)的一次执行过程;线程不占有内存空间,它包括在进程的内存空间中。在同一个进程内,多个线程共享进程的资源;一个进程至少有一个线程。

multitip.exe是什么进程multitip.exe是什么进程Mar 13, 2023 pm 01:41 PM

multitip.exe是360内置的广告弹窗进程,其中包括了今日优品、焦点资讯、每日趣玩等广告弹窗;其删除方法:1、找到并删除sesvc.exe文件;2、在原来的目录下建立一个sesvc.exe目录,然后将这个目录的所有用户的“完全控制”权限设置为“拒绝”即可。

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!