中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

公司網(wǎng)站seo優(yōu)化的線上營銷推廣方式

公司網(wǎng)站seo優(yōu)化的,線上營銷推廣方式,高密做網(wǎng)站哪家好,浠水做網(wǎng)站的進程間通信 1. 進程間通信的概念2. 匿名管道pipe3. 命名管道FIFO4. 內(nèi)存映射區(qū) 1. 進程間通信的概念 在Linux的環(huán)境下,進程地址空間是相互獨立的,每個進程有著各自不同的用戶地址空間。一個進程不能訪問另一個進程中的內(nèi)容,要進行數(shù)據(jù)交換必…

進程間通信

  • 1. 進程間通信的概念
  • 2. 匿名管道pipe
  • 3. 命名管道FIFO
  • 4. 內(nèi)存映射區(qū)

1. 進程間通信的概念

在Linux的環(huán)境下,進程地址空間是相互獨立的,每個進程有著各自不同的用戶地址空間。一個進程不能訪問另一個進程中的內(nèi)容,要進行數(shù)據(jù)交換必須要通過內(nèi)核,在內(nèi)核中開辟塊緩沖區(qū),一個進程將數(shù)據(jù)從用戶空間拷貝到內(nèi)核緩沖區(qū)中,另一個進程從內(nèi)核緩沖區(qū)中將數(shù)據(jù)讀走。內(nèi)核提供的這種機制稱為進程間通信(IPC)。

在進程間完成數(shù)據(jù)傳輸需要借助操作系統(tǒng)提供的特殊方法,比如文件、管道、FIFO、內(nèi)存映射區(qū)、消息隊列、信號、套接字等。如今常用的進程間通信主要有管道(最簡單)、信號(開銷最小)、內(nèi)存映射區(qū)(無血緣關(guān)系)、本地套接字(最穩(wěn)定)。

2. 匿名管道pipe

管道是一種最基本的進程間通信機制,也稱為匿名管道,應(yīng)用于有血緣關(guān)系的進程間進行通信。管道的本質(zhì)是一塊內(nèi)核緩沖區(qū),內(nèi)部使用的環(huán)形隊列實現(xiàn),由兩個文件描述符進行引用,其中一個表示讀端,另一個表示寫端。管道的數(shù)據(jù)從管道的寫端流入管道,從讀端流出。當兩個進程都死亡的時候,管道也會自動消失。管道不管讀端還是寫端默認都是阻塞的。管道的默認緩沖區(qū)大小為4K,可以使用ulimit -a命令獲取大小。

在這里插入圖片描述

管道的數(shù)據(jù)一旦被讀走,便不在管道中存在,不可以反復(fù)讀取。管道的數(shù)據(jù)只能在一個方向上流動,如果需要實現(xiàn)雙向流動則需要使用兩個管道。匿名管道只能在有血緣關(guān)系的進程中使用。我們用pipe函數(shù)來創(chuàng)建管道。

在這里插入圖片描述

pipe函數(shù)的原型如下:

       #include <unistd.h>int pipe(int pipefd[2]); // 創(chuàng)建管道

其中pipefd為管道寫端和讀端的文件描述符,其中pipefd[0]為管道讀端的文件描述符,pipefd[1]為管道寫端的文件描述符。當函數(shù)調(diào)用成功創(chuàng)建了管道返回0,失敗則返回-1并設(shè)置errno。

在使用匿名管道進行通信的時候,一般是先用pipe函數(shù)創(chuàng)建管道,再使用fork函數(shù)創(chuàng)建子進程。這樣父子進程就具有了相同的文件描述符,就會指向同一個管道。

在管道的通信中,讀寫數(shù)據(jù)也是使用readwrite。管道的示例代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>int main()
{// 創(chuàng)建管道//int pipe(int pipefd[2]);int fd[2];int ret = pipe(fd);if(ret < 0){perror("pipe error");return -1;}// 創(chuàng)建子進程pid_t pid = fork();if(pid < 0){perror("fork error");return -1;}else if(pid == 0){// 子進程關(guān)閉寫端close(fd[1]);char buf[1024];memset(buf, 0x00, sizeof(buf));sleep(5);read(fd[0], buf, sizeof buf);printf("child: read over, pid = [%d], fpid = [%d], buf = [%s]\n", getpid(), getppid(), buf);}else{// 父進程關(guān)閉讀端close(fd[0]);write(fd[1], "helloworld", strlen("helloworld"));printf("father: write over, pid = [%d], fpid = [%d]\n", getpid(), getppid());pid_t wpid = wait(NULL);printf("child [%d] is dead!\n", wpid);}return 0;
}

在shell中我們查詢某一個進程的時候我們會使用ps -ef | grep --color=auto bash,這里的|就是管道。我們使用父進程進程去執(zhí)行ps -ef命令,由于我們需要交給grep去作為輸入,所以在父進程中需要將輸出重定向到管道的寫端。子進程執(zhí)行grep的時候會從輸入進行讀取內(nèi)容,因此我們需要將輸入重定向到管道讀端。重定向的時候需要使用dup2函數(shù),需要執(zhí)行命令則需要使用execlexeclp函數(shù),示例程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>int main()
{// 創(chuàng)建管道int pipefd[2];int ret = pipe(pipefd);if(ret < 0){// 創(chuàng)建失敗perror("pipe error");return -1;}// 創(chuàng)建子進程pid_t pid = fork();if(pid < 0){// 創(chuàng)建失敗perror("fork error");return -1;}else if(pid == 0){// 子進程關(guān)閉寫端close(pipefd[1]);// 將標準輸入重定向到管道讀端dup2(pipefd[0], STDIN_FILENO);execlp("grep", "grep", "--color=auto", "bash", NULL);perror("execlp error");}else {// 父進程關(guān)閉讀端close(pipefd[0]);// 將標準輸出重定向到管道寫端dup2(pipefd[1], STDOUT_FILENO);execlp("ps", "ps", "-ef", NULL);perror("execlp error");}return 0;
}

當管道有數(shù)據(jù)的時候,read可以正常讀,并返回讀出來的字節(jié)數(shù);當管道沒有數(shù)據(jù)的時候,若寫端全部關(guān)閉,則read函數(shù)解出阻塞狀態(tài),返回0,相當于讀文件讀到了尾部。若寫端沒有關(guān)閉,則read阻塞。

若讀端全部關(guān)閉,進行寫操作的時候則管道會破裂,進程終止,內(nèi)核會給當前進程發(fā)送SIGPIPE信號。若讀端沒有完全關(guān)閉,緩沖區(qū)寫滿了則write會阻塞,緩沖區(qū)沒有滿則可以繼續(xù)write

管道默認兩端都是阻塞的,若要設(shè)置為非阻塞,則可以使用前面提過的fcntl函數(shù)。首先使用F_GETFL獲取flags,然后在添加O_NONBLOCK使用F_SETFL設(shè)置即可。當讀端設(shè)置為非阻塞狀態(tài)的時候,會有以下四種情況:

  • 寫端沒有關(guān)閉,管道中沒有數(shù)據(jù)可讀,則read返回-1。
  • 寫端沒有關(guān)閉,管道中有數(shù)據(jù)可讀,則read返回實際讀到的字節(jié)數(shù)。
  • 寫端已經(jīng)關(guān)閉,管道中有數(shù)據(jù)可讀,則read返回實際讀到的字節(jié)數(shù)。
  • 寫端已經(jīng)關(guān)閉,管道中沒有數(shù)據(jù)可讀,則read返回0。

設(shè)置的流程為:

int flags = fcntl(fd[0], F_GETFL, 0);
flags = flags | O_NONBLOCK;
fcntl(fd[0], F_SETFL, flags);

除了前面使用的ulimit -a可以查看到管道緩沖區(qū)的大小之外,也可以使用fpathconf函數(shù),該函數(shù)的原型為:

       #include <unistd.h>long fpathconf(int fd, int name); 

這個函數(shù)會根據(jù)name的參數(shù)設(shè)置返回文件描述符fd對應(yīng)文件的配置內(nèi)容。比如獲取管道緩沖區(qū)則需要把name設(shè)置為_PC_PIPE_BUF。如下面查看管道的緩沖區(qū)大小。

printf("pipe size = [%ld]\n", fpathconf(fd[0], _PC_PIPE_BUF));
printf("pipe size = [%ld]\n", fpathconf(fd[1], _PC_PIPE_BUF));

更多的name參數(shù)設(shè)置可以使用man fpathconf查詢幫助文檔。

3. 命名管道FIFO

使用pipe管道只能實現(xiàn)有血緣關(guān)系的兩個進程間的通信,那么對于兩個沒有血緣關(guān)系的進程又應(yīng)該怎么實現(xiàn)呢?則需要這一節(jié)的命名管道FIFO

FIFO是Linux上基于文件類型的一種通信方式,文件類型為p,但是FIFO在磁盤上并沒有數(shù)據(jù)塊,文件大小為0,僅僅用于標識內(nèi)核中的一條通道。進程可以通過read或者write函數(shù)去對這一條通道進行操作,也就是內(nèi)核緩沖區(qū),這樣就實現(xiàn)了進程間的通信。

要使用命名管道,就得先創(chuàng)建命名管道文件,創(chuàng)建管道文件使用mkfifo函數(shù),該函數(shù)的原型為:

       #include <sys/types.h>#include <sys/stat.h>int mkfifo(const char *pathname, mode_t mode);

其中參數(shù)第一個pathname表示管道的路徑名,mode表示權(quán)限,使用一個三位八進制數(shù)表示。創(chuàng)建成功函數(shù)返回0,創(chuàng)建失敗則函數(shù)返回-1并設(shè)置errno。

FIFO嚴格遵守先進先出的規(guī)則,也就是對于管道的讀總是從管道的開始處返回數(shù)據(jù),而對于管道的寫則是添加到末尾。因此命名管道不支持使用lseek等對文件定位的操作。

使用FIFO完成進程間通信的示意圖如下:

在這里插入圖片描述

既然是兩個進程,也就是說兩個進程中的程序都需要打開管道,也就是需要找到文件。若寫進程沒有打開就去使用讀進程,則可能因為管道的文件不存在而報錯。因此我們在使用管道或者創(chuàng)建管道之前要先判斷文件是否存在。這個可以使用access函數(shù)實現(xiàn),該函數(shù)的原型為:

       #include <unistd.h>int access(const char *pathname, int mode);

該函數(shù)的第一個參數(shù)pathname是文件的路徑,第二個參數(shù)mode表示要測試的模式,有四個參數(shù)可以傳,分別為:

  • F_OK: 文件存在
  • R_OK:有讀權(quán)限
  • W_OK:有寫權(quán)限
  • X_OK:有執(zhí)行權(quán)限

當有對應(yīng)的權(quán)限或者文件存在的時候,該函數(shù)的返回值為0,若沒有對應(yīng)權(quán)限或者文件不存在則該函數(shù)返回-1。

接下來我們實現(xiàn)兩個無血緣關(guān)系之間的進程間通信。代碼如下:

fifo_write.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>// FIFO 寫進程
int main()
{// 創(chuàng)建FIFO文件// int access(const char *pathname, int mode);int ret = access("./myfifo", F_OK);if(ret < 0){// int mkfifo(const char *pathname, mode_t mode);ret = mkfifo("./myfifo", 0777);if(ret < 0){perror("mkfifo error");return -1;}}// 打開FIFOint fd = open("./myfifo", O_RDWR);if(fd < 0){perror("open error");return -1;}// 傳輸數(shù)據(jù)char buf[1024] = "hello world";write(fd, buf, strlen(buf));sleep(1);// 關(guān)閉FIFOclose(fd);return 0;
}

fifo_read.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>// FIFO 讀進程端
int main()
{// 判斷創(chuàng)建FIFOint ret = access("./myfifo", F_OK);if(ret < 0){int ret = mkfifo("./myfifo", 0777);if(ret < 0){perror("mkfifo error");return -1;}}// 打開FIFOint fd = open("./myfifo", O_RDWR);if(fd < 0){perror("open error");return -1;}// 接收數(shù)據(jù)char buf[1024];memset(buf, 0x00, sizeof buf);read(fd, buf, sizeof buf);printf("%s\n", buf);// 關(guān)閉FIFOclose(fd);return 0;
}

在上述代碼中,只要運行,不管是讀進程還是寫進程先運行,只要寫進程沒有往管道中寫數(shù)據(jù),讀進程都會阻塞在read處。直到寫進程調(diào)用write函數(shù)往管道中寫數(shù)據(jù)之后讀進程才會讀出來管道中的數(shù)據(jù)輸出。

4. 內(nèi)存映射區(qū)

內(nèi)存映射區(qū)是將一個磁盤文件與內(nèi)存空間的一個緩沖區(qū)向映射。當我們在緩沖區(qū)中讀取數(shù)據(jù)的時候,就相當于在文件中讀取相應(yīng)的字節(jié)。若我們向緩沖區(qū)中寫數(shù)據(jù),則會把數(shù)據(jù)寫入對應(yīng)的文件之中。這樣就可以在不使用read函數(shù)和write函數(shù)啊的情況下使用指針完成IO操作。

在這里插入圖片描述

映射這個過程可以使用mmap函數(shù)實現(xiàn)。解除映射可以使用munmap實現(xiàn)。函數(shù)的原型以及參數(shù)如下:

       #include <sys/mman.h>// 函數(shù)作用: 建立存儲映射區(qū)// 返回值: 成功:返回創(chuàng)建的映射區(qū)首地址//		  失敗: 返回MAP_FAILED宏, 實際上就是(void *)-1// 參數(shù): addr: 指定映射的起始地址,通常設(shè)為NULL,由系統(tǒng)指定//      length: 映射到內(nèi)存的文件長度//       prot: 映射區(qū)的保護方式,最常用的有//                PROT_READ   				讀//                PROT_WRITE  				寫//                PROT_READ | PORT_WRITE    讀寫//       flags: 映射區(qū)的特性,可以設(shè)置以下//                MAP_SHARED   寫入映射區(qū)的數(shù)據(jù)會寫回文件,且允許//							   其它映射改文件的進程共享。//                MAP_PRIVATE  對映射區(qū)的寫入操作會產(chǎn)生一個映射區(qū)的復(fù)//  						 	制,對此區(qū)域所做的修改不會寫回原文件。//                MAP_ANONYMOUS  匿名映射區(qū),需要結(jié)合MAP_SHARED使用。// 	      fd: 代表要映射的文件,由open函數(shù)返回的文件描述符//        offset: 以文件開始出的偏移量,必須是4K的整數(shù)倍,通常為0,表示//                從文件頭開始映射void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);// 函數(shù)作用: 釋放由mmap函數(shù)建立的存儲映射區(qū)// 返回值: 成功返回0,失敗返回-1并設(shè)置errno// 參數(shù): addr: 調(diào)用mmap函數(shù)成功返回的映射區(qū)首地址//  	 length: 映射區(qū)的大小int munmap(void *addr, size_t length);

需要注意到的是,mmap函數(shù)不能開辟長度為0的存儲映射區(qū)。在使用mmap函數(shù)創(chuàng)建映射區(qū)的過程中,隱含著一次對映射文件的讀操作,將文件讀取到映射區(qū)。當我們將flags設(shè)置為MAP_SHARED的時候,要求映射區(qū)的權(quán)限應(yīng)該小于或者等于文件打開的權(quán)限,這是出于對映射區(qū)的保護。而對于MAP_PRIVATE,則是沒有這個必要,因為mmap中的權(quán)限是對內(nèi)存的限制。

在映射區(qū)建立之后,映射區(qū)的釋放是與文件的關(guān)閉無關(guān)的,所以在映射區(qū)建立之后就可以關(guān)閉文件。在創(chuàng)建映射區(qū)的時候,使用mmap函數(shù)常常會出現(xiàn)總線錯誤,通常是因為共享文件存儲空間大小引起的。所以創(chuàng)建映射區(qū)的時候出錯的概率比較高,因此一定要檢查函數(shù)的返回值,確保映射區(qū)建立成功了再進行后續(xù)的操作。使用munmap函數(shù)的時候,傳入的地址一定要是mmap函數(shù)的返回值,一定不要改變指針的指向。其中函數(shù)的參數(shù)中offset也是需要注意的,不能隨便指定,必須要是4K的整數(shù)倍才行。

下面給出一個關(guān)于關(guān)于有血緣關(guān)系的進程間的通信示例。

//使用mmap完成有血緣關(guān)系進程間的通信
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>int main()
{//使用mmap函數(shù)建立共享映射區(qū)//void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);int fd = open("test.log", O_RDWR);if(fd < 0){perror("open error");return -1;}int len = lseek(fd, 0, SEEK_END);void *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if(addr == MAP_FAILED){perror("mmap error");return -1;}close(fd);//創(chuàng)建子進程pid_t pid = fork();if(pid < 0){perror("fork error");return -1;}else if(pid == 0){//子進程sleep(2);char *p = (char *)addr;printf("[%s]\n", p);}else{//父進程memcpy(addr, "hello world", strlen("hello world"));wait(NULL);}return 0;
}

共享存儲映射區(qū)也可以用于沒有血緣關(guān)系的兩個進程。

寫進程

// 使用mmap完成沒有血緣關(guān)系的進程間的通信
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>// 寫進程
int main()
{// 使用mmap函數(shù)建立共享映射區(qū)int fd = open("test.log", O_RDWR);if(fd < 0){perror("open error");return -1;}int len = lseek(fd, 0, SEEK_END);// 建立共享映射區(qū)void *addr = mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0);if(addr == MAP_FAILED){perror("mmap error");return -1;}close(fd);memcpy(addr, "Good morning", strlen("Good morning"));return 0;
}

讀進程

// 使用mmap完成沒有血緣關(guān)系的兩個進程間的通信
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>// 讀進程端
int main()
{// 使用mmap函數(shù)建立共享映射區(qū)int fd = open("test.log", O_RDONLY);if(fd < 0){perror("open error");return -1;}int len = lseek(fd, 0, SEEK_END);// 建立共享映射區(qū)void *addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);if(addr == MAP_FAILED){perror("mmap error");return -1;}char *p = (char *)addr;printf("[%s]\n", p);return 0;
}

上面的共享存儲映射區(qū)都是有名字的,我們也可以創(chuàng)建匿名的共享存儲映射區(qū)。匿名映射區(qū)是不需要使用文件去創(chuàng)建的,因此沒有血緣關(guān)系的兩個進程不能使用匿名映射區(qū)通信。在使用匿名共享映射區(qū)的時候,文件的描述符一般傳為-1。關(guān)于匿名共享映射區(qū)的示例代碼如下:

// 建立匿名共享映射區(qū)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fcntl.h>int main()
{void *addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);if(addr == MAP_FAILED){perror("mmap error");return -1;}pid_t pid = fork();if(pid < 0){perror("fork error");return -1;}else if(pid == 0){sleep(2);char *p = (char *)addr;printf("[%s]\n", p);}else{memset(addr, 0x00, 4096);memcpy(addr, "hello world", strlen("hello world"));wait(NULL);}return 0;
}

后續(xù)博客關(guān)于函數(shù)原型以及作用均以注釋的形式寫在代碼中以便直觀

http://www.risenshineclean.com/news/33585.html

相關(guān)文章:

  • 騰訊云 wordpress教程視頻seo外鏈推廣
  • wordpress+技術(shù)類模板網(wǎng)站seo優(yōu)化有哪些方面
  • 在什么網(wǎng)站可以接活做梅州網(wǎng)絡(luò)推廣
  • 布料市場做哪個網(wǎng)站好代寫軟文
  • 動漫網(wǎng)站設(shè)計方案華為手機軟文范文300
  • 網(wǎng)站群如何做網(wǎng)站seo快速優(yōu)化軟件
  • 單位網(wǎng)站中文域名到期續(xù)費seo的培訓班
  • 梧州網(wǎng)站建設(shè)設(shè)計百度服務(wù)電話在線人工
  • 做網(wǎng)站用什么字體字號seo技術(shù)優(yōu)化服務(wù)
  • wordpress換域名了 登陸不了五年級下冊數(shù)學優(yōu)化設(shè)計答案
  • 域名 備案 沒有網(wǎng)站嗎網(wǎng)絡(luò)營銷的有哪些特點
  • 怎么自己做網(wǎng)站嚇別人佛山seo聯(lián)系方式
  • 剛注冊公司怎么做網(wǎng)站seo案例分析100例
  • 云推廣關(guān)鍵詞優(yōu)化是怎么弄的
  • 公司網(wǎng)站的管理和維護uc瀏覽網(wǎng)頁版進入
  • 制作網(wǎng)站步驟新媒體營銷案例ppt
  • 網(wǎng)頁設(shè)計的動態(tài)網(wǎng)站怎么做騰訊企點官網(wǎng)下載
  • 前端和網(wǎng)站建設(shè)的區(qū)別友情手機站
  • 宜興建設(shè)局網(wǎng)站長沙seo行者seo09
  • wordpress采集處理樣式廣東優(yōu)化疫情防控措施
  • 做網(wǎng)站3個月搜索引擎營銷流程是什么?
  • 簡約風格網(wǎng)站代哥seo
  • 男和女做暖暖網(wǎng)站網(wǎng)絡(luò)銷售怎么找客戶
  • 做網(wǎng)站練手優(yōu)化大師電腦版
  • seo黑帽技術(shù)工具陜西seo顧問服務(wù)
  • 真人做爰網(wǎng)站怎么提交網(wǎng)址讓百度收錄
  • 做網(wǎng)站常用代碼向右浮動怎么寫凡科網(wǎng)怎么建網(wǎng)站
  • 有了 ftp服務(wù)器密碼 怎么改網(wǎng)站給我免費播放片高清在線觀看
  • 網(wǎng)站域名代辦百度搜索鏈接
  • 國外做的好的醫(yī)療網(wǎng)站網(wǎng)站域名服務(wù)器查詢