1. 程式人生 > >【Linux】Linux 下多程序程式設計詳解

【Linux】Linux 下多程序程式設計詳解

一.多程序程式的特點

   程序是一個具有獨立功能的程式關於某個資料集合的一次可以併發執行的執行活動,是處

於活動狀態的計算機程式。

   程序作為構成系統的基本細胞,

不僅是系統內部獨立執行的實體,

而且是獨立競爭資源的基本實體。

   程序是資源管理的最小單位,執行緒是程式執行的最小單位。程序管理著資源(比

如 cpu、記憶體、檔案等等),而將執行緒分配到某個 cpu 上執行。在作業系統設計

上,從程序演化出執行緒,最主要的目的就是更好的支援多處理器系統和減小上下

文切換開銷。

   程序的狀態 系統為了充分的利用資源,對程序區分了不同的狀態.將程序分為新

建,執行,阻塞,就緒和完成五個狀態.

    新建 表示程序正在被建立,

    執行 是程序正在執行,

    阻塞 是程序正在等待某一個事件發生,

    就緒 是表示系統正在等待 CPU 來執行命令,

    完成 表示程序已經結束了系統正在回收資源.

由於 UNIX 系統是分時多使用者系統, CPU 按時間片分配給各個使用者使用,而在實質上應

該說 CPU 按時間片分配給各個程序使用, 每個程序都有自己的執行環境以使得在 CPU 做進

程切換時不會"忘記"該程序已計算了一半的"半成品”. 以 DOS 的概念來說, 程序的切換都

是一次"DOS 中斷"處理過程, 包括三個層次:

   1) 使用者資料的儲存: 包括正文段(TEXT), 資料段(DATA,BSS), 棧段(STACK), 共享內

存段(SHARED MEMORY)的儲存.

   2) 暫存器資料的儲存: 包括 PC(program counter,指向下一條要執行的指 令的地址),

PSW(processor status word,處理機狀態字), SP(stack pointer,棧指標), PCBP(pointer of

process control block,程序控制塊指標), FP(frame pointer,指向棧中一個函式的 local

變數的首地址), AP(augument pointer,指向棧中函式呼叫的實參位置), ISP(interrupt

stack pointer,中斷棧指標), 以及其他的通用暫存器等.

   3) 系統層次的儲存:

包括 proc,u,虛擬儲存空間管理表格,中斷處理棧.以便於該程序再一次得到 CPU 時

間片時能正常執行。 既然系統已經處理好所有這些中斷處理的過程, 我們做程式

還有什麼要擔心 的呢? 我們儘可以使用系統提供的多程序的特點, 讓幾個程式精

誠合作, 簡單而又高效地把結果給它搞出來。

多程序程式的

一些突出的特點:

  並行化

  簡單有序

  互不干擾

  事務化

二.常用的多程序程式設計的系統呼叫

1)功能:建立一個新的程序.

語法:

#include <unistd.h>

#include <sys/types.h>

pid_t fork();

  說明:本系統呼叫產生一個新的程序, 叫子程序, 是呼叫程序的一個複製品. 呼叫程序叫父進

程, 子程序繼承了父程序的幾乎所有的屬性。

  簡述:fork() 呼叫成功時,分別返回兩個整數,對父程序返回 〉0 的整數,對子程序返回

0,

程序:程式碼段(程式程式碼)

     堆疊段(區域性變數、函式返回地址、函式引數)

     資料段(全域性變數、常數等)

在 Linux 系統中,系統呼叫 fork 後,核心為完成系統呼叫 fork 要進行幾步操作:

     第一步,為新程序在程序表中分配一個表項。系統對一個普通使用者可以同時執行的進

程數是有限制的,對超級使用者沒有該限制,但不能超過程序表的最大表項的

數目。

     第二步,給子程序一個唯一的程序標識號(PID)

     第三步,複製一個父程序的程序表項的副本給子程序。核心初始化子程序的程序表項

時,是從父程序處拷貝的。所以子程序擁有與父程序一樣的 uid、當前目錄、

當前根、使用者檔案描述符表等。

     第四步,

父程序相連的檔案表和索引節點表的引用數加 1。

這些檔案自動地與該子

程序相連。

     第五步,核心為子程序建立使用者級上下文。核心為子程序的程式碼段分配記憶體,並複製

父程序的區內容,生成的是程序的靜態部分。

     第六步,生成程序的動態部分,然後對父程序返回子程序的 pid,對子程序返回 0。

從父程序拷貝的內容主要有:

使用者識別符號,包括實際使用者號(real)和有效使用者號(effective)

環境變數

開啟的檔案描述符、套接字描述符

訊號處理設定

堆疊

目錄

程序組標誌(process ID)

會晤組標誌(session ID)

正文

子程序特有內容:

程序號

父程序號

程序執行時間

未處理的訊號被處理為空

不繼承非同步的輸入輸出操作

函式執行過程:

1 核心在系統程序表中,建立一個新條目;

2 複製父程序內容(已開啟的檔案描述符、堆疊、正文等)

3 修改兩者的堆疊,給父程序返回子程序號,給子程序返回 0(父程序知道每個子程序

的標誌號,而子程序可根據需要呼叫 getppid() 來獲得父程序的標誌號)

例子:

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

int main(int argc,char *argv[])

{

    pid_t pid;

    if((pid=fork())==0)//對子程序返回==0的整數

    {

        printf("This is Child fork\n");//子程序程式碼

                printf("Child pid= %d\n",pid);//子程序程式碼

        //exit(0);

    }

    else if(pid>0) //對父程序返回 〉0 的整數

    {

        printf("This is Father fork\n");//父程序程式碼

                printf("Father pid= %d\n",pid);//子程序程式碼

        //exit(0);

    }

    else

    {

        printf("Error");

        exit(1);

    }

}

$gcc -o fork fork.c

$./fork

This is Father fork

Father pid= 6250

This is Child fork

Child pid= 0

2)system()

應用程式

fork ( )

父程序

子程序 1

子程序 2

子程序執行指定的命令

     功能:產生一個新的程序, 子程序執行指定的命令.

     語法:

           #include <stdio.h>

           #include <stdlib.h>

           int system(string)

            char *string;

     說明:

本呼叫將引數 string 傳遞給一個命令直譯器(一般為 sh)執行, 即 string 被解釋為一條命

令, 由 sh 執行該命令.若引數 string 為一個空指標則為檢查命令直譯器是否存在.

該命令可以同命令行命令相同形式, 但由於命令做為一個引數放在系統呼叫中, 應注意

編譯時對特殊意義字元的處理. 命令的查詢是按 PATH 環境變數的定義的. 命令所生成的後

果一般不會對父程序造成影響.

     返回值:當引數為空指標時, 只有當命令直譯器有效時返回值為非零. 若引數不為空指

針, 返回值為該命令的返回狀態(同 waitpid())的返回值. 命令無效或語法錯誤則返回非零值,

所執行的命令被終止. 其他情況則返回-1.

      例子:

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

int main(int argc,char *argv[])

{

    char command[81];  

    sprintf(command,"ps aux");

    system(command);

}

3)exec()

功能:執行一個檔案

語法

#include <unistd.h>

int execve(const char* path, char* const* argv,char* const* envp);

int execl(const char* path, char* arg,...);

int execp(const char* file, char* arg,...);

int execle(const char* path, const char* argv,...,char* const* envp);

int execv(const char* path, char* const* arg);

int execvp(const char* file, char* const* arg);

說明:

     exec 函式族的作用是根據指定的檔名找到可執行檔案,並用它來取代呼叫程序的內

容,換句話說,就是在呼叫程序內部執行一個可執行檔案

     其中只有 execve 是真正意義上的系統呼叫,其它都是在此基礎上經過包裝的庫函式。

與一般情況不同,exec 函式族的函式執行成功後不會返回,因為呼叫程序的實體,包

括程式碼段,資料段和堆疊等都已經被新的內容取代,只留下程序 ID 等一些表面上的資訊仍

保持原樣,頗有些神似"三十六計"中的"金蟬脫殼"。看上去還是舊的軀殼,卻已經注入了新

的靈魂。只有呼叫失敗了,它們才會返回一個-1,從原程式的呼叫點接著往下執行。

fork()和 exec()這兩個函式,前者用於並行執行,父、子程序執行相同正文中的不同

部分;後者用於呼叫其他程序,父、子程序執行不同的正文,呼叫前,一般應為子程序創造

一個乾淨的環境。

      fork()以後,父、子程序共享程式碼段,並只重新建立資料有改變的頁(段頁式管理)

      exec()以後,建立新的程式碼段,用被呼叫程式的內容填充。

      前者的子程序執行後續的公共程式碼,後者的子程序不執行後續的公共程式碼。

      父、子程序以及各個子程序執行的順序不定。

例子:printf("now this process will be ps command\n");

      execl("/bin/ps","ps","-ef",NULL);

4)popen()

功能:初始化從/到一個程序的管道.

語法:

#include <stdio.h>

FILE *popen(command,type)

char *command,type;

說明:本系統呼叫在呼叫程序和被執行命令間建立一個管道.

引數 command 做為被執行的命令列.type 做為 I/O 模式,"r"為從被

執行命令讀,"w"為向被執行命令寫.返回一個標準流指標,做為管

道描述符,向被執行命令讀或寫資料(做為被執行命令的 STDIN 或

STDOUT)該系統呼叫可以用來在程式中呼叫系統命令,並取得命令

的輸出資訊或者向命令輸入資訊.

返回值:不成功則返回 NULL,成功則返回管道的檔案指標.

5)pclose()

    功能:關閉到一個程序的管道.

    語法:

       #include <stdio.h>

       int pclose(strm)

       FILE *strm;

     說明:本系統呼叫用於關閉由 popen()開啟的管道,並會等待由 popen()

啟用的命令執行結束後,關閉管道後讀取命令返回碼.

     返回值:若關閉的檔案描述符不是由 popen()開啟的,則返回-1.

     例子:

   printf("now this process will call popen system call\n");

   FILE * fd;

   if ((fd=popen("ps -ef","r"))==NULL) {

         printf("call popen failed\n");

         return;

    }  

    else {

         char str[80];

         while (fgets(str,80,fd)!=NULL)

                   printf("%s\n",str);

     }

   pclose(fd);

6)wait()

功能:等待一個子程序返回並修改狀態

語法:

#include <sys/types.h>

#include <sys/wait.h>

pid_t wait(stat_loc)

int *stat_loc;

說明:允許呼叫程序取得子程序的狀態資訊.呼叫程序將會掛起直到其

一個子程序終止.

返回值:等待到一個子程序返回時,返回值為該子程序號,否則返回值為

-1.stat_loc返回子程序的返回值.

例子:/*父程序*/

if (fork()>0) {

     wait((int *)0);

    /*父程序等待子程序的返回*/

}

else {

    /*子程序處理過程*/

     exit(0);

}

7)waitpid()

    功能:等待指定程序號的子程序的返回並修改狀態

    語法:

        #include <sys/types.h>

        #include <sys/wait.h>

        pid_t waitpid(pid,stat_loc,options)

        pid_t pid;

        int *stat_loc,options;

     說明:當 pid 等於-1,options 等於 0 時,該系統呼叫等同於 wait().否則該

系統呼叫的行為由引數 pid 和 options 決定.

pid 指定了一組父程序要求知道其狀態的子程序:

           -1:要求知道任何一個子程序的返回狀態.

           >0:要求知道程序號為 pid 值的子程序的狀態.

            <-1:要求知道程序組號為 pid 的絕對值的子程序的狀態.

options 引數為以位元方式表示的標誌以或運算組成的點陣圖,每個

標誌以位元組中某個位元置 1 表示:

WUNTRACED:報告任何未知而又已停止執行的指定程序號的子進

程的狀態.該子程序的狀態自停止執行時起就沒有被報告 過.

WCONTINUED:報告任何繼續執行的指定程序號的子程序的狀態,

該子程序的狀態自繼續執行起就沒有被報告過.

WHOHANG:若呼叫本系統呼叫時,指定程序號的子程序的狀態目

前並不是立即有效的(即可被立即讀取的),呼叫程序並被 暫停執行.

WNOWAIT:保持將其狀態設定在 stat_loc 的程序在可等待狀態.

該程序將等待直到下次被要求其返回狀態值.

返回值:等待到一個子程序返回時,返回值為該子程序號,否則返回值為 1.

同時 stat_loc 返回子程序的返回值.

例子:pid_t pid;

int stat_loc; /*父程序*/

if ((pid="fork())">0) {

waitpid(pid,&stat_loc,0);

/*父程序等待程序號為 pid 的子程序的返回*/

}

else {

/*子程序的處理過程*/

exit(1);

}

/*父程序*/

printf("stat_loc is [%d]\n",stat_loc);

/*字串"stat_loc is [1]"將被打印出來*/

設定程序組號和會話號

2.8.setpgrp()

功能:設定程序組號和會話號.

語法:

#include <sys/types.h>

pid_t setpgrp()

說明:若呼叫程序不是會話首程序.將程序組號和會話號都設定為與它

的程序號相等.並釋放呼叫程序的控制終端.

返回值:呼叫成功後,返回新的程序組號.

例子:/*父程序處理*/

if (fork()>0) {

/*父程序處理*/

}

else {

setpgrp();

/*子程序的程序組號已修改成與它的程序號相同*/

exit(0);

}

2.9.exit()

終止程序

功能:終止程序.

語法:

#include <stdlib.h>

void exit(status)

int status;

說明:呼叫程序被該系統呼叫終止.引起附加的處理在程序被終止前全

部結束.

返回值:無

2.10.signal()

訊號管理功能

功能:訊號管理功能

語法:

#include <signal.h>

void (*signal(sig,disp))(int)

int sig;

void (*disp)(int);

void (*sigset(sig,disp))(int)

int sig;

void (*disp)(int);

int sighold(sig)

int sig;

int sigrelse(sig)

int sig;

int sigignore(sig)

int sig;

int sigpause(sig)

int sig;

說明:這些系統呼叫提供了應用程式對指定訊號的簡單的訊號處理.

signal()和 sigset()用於修改訊號定位.引數 sig 指定訊號(除了

SIGKILL 和 SIGSTOP,這兩種訊號由系統處理,使用者程式不能捕捉到).

disp 指定新的訊號定位,即新的訊號處理函式指標.可以為

SIG_IGN,SIG_DFL 或訊號控制代碼地址.

若使用 signal(),disp 是訊號控制代碼地址,sig 不能為 SIGILL,SIGTRAP

或 SIGPWR,收到該訊號時,系統首先將重置 sig 的訊號控制代碼為 SIG_DFL,

然後執行訊號控制代碼.

若使用 sigset(),disp 是訊號控制代碼地址,該訊號時,系統首先將該

訊號加入呼叫程序的訊號掩碼中,然後執行訊號控制代碼.當訊號控制代碼

執行結束

後,系統將恢復呼叫程序的訊號掩碼為訊號收到前的狀態.另外,

使用 sigset()時,disp 為 SIG_HOLD,則該訊號將會加入呼叫程序的

訊號掩碼中而訊號的定位不變.

sighold()將訊號加入呼叫程序的訊號掩碼中.

sigrelse()將訊號從呼叫程序的訊號掩碼中刪除.

sigignore()將訊號的定位設定為 SIG_IGN.

sigpause()將訊號從呼叫程序的訊號掩碼中刪除,同時掛起呼叫

程序直到收到訊號.

若訊號 SIGCHLD 的訊號定位為 SIG_IGN,則呼叫程序的子程序在終

止時不會變成僵死程序.呼叫程序也不用等待子程序返回並做相

應處理.

返回值:呼叫成功則 signal()返回最近呼叫 signal()設定的 disp 的值.

否則返回 SIG_ERR.

例子一:設定使用者自己的訊號中斷處理函式,以 SIGINT 訊號為例:

int flag=0;

void myself()

{

flag=1;

printf("get signal SIGINT\n");

/*若要重新設定 SIGINT 訊號中斷處理函式為本函式則執行以

*下步驟*/

void (*a)();

a=myself;

signal(SIGINT,a);

flag=2;

}

main()

{

while (1) {

sleep(2000); /*等待中斷訊號*/

if (flag==1) {

printf("skip system call sleep\n");

exit(0);

}

if (flag==2) {

printf("skip system call sleep\n");

printf("waiting for next signal\n");

}

}

}

2.11.kill()

向一個或一組程序傳送一個訊號

功能:向一個或一組程序傳送一個訊號.

語法:

#include <sys/types.h>

#include <signal.h>

int kill(pid,sig);

pid_t pid;

int sig;

說明:本系統呼叫向一個或一組程序傳送一個訊號,該訊號由引數 sig 指

定,為系統給出的訊號表中的一個.若為 0(空訊號)則檢查錯誤但

實際上並沒有傳送訊號,用於檢查 pid 的有效性.

pid 指定將要被髮送訊號的程序或程序組.pid 若大於 0,則訊號將

被髮送到程序號等於 pid 的程序;若 pid 等於 0 則訊號將被髮送到所

有的與傳送訊號程序同在一個程序組的程序(系統的特殊程序除

外);若 pid 小於-1,則訊號將被髮送到所有程序組號與 pid 絕對值

相同的程序;若 pid 等於-1,則訊號將被髮送到所有的程序(特殊系

統程序除外).

訊號要傳送到指定的程序,首先呼叫程序必須有對該程序傳送信

號的許可權.若呼叫程序有合適的優先順序則具備有許可權.若呼叫程序

的實際或有效的 UID 等於接收訊號的程序的實際 UID 或用 setuid()

系統呼叫設定的 UID,或 sig 等於 SIGCONT 同時收發雙方程序的會話

號相同,則呼叫程序也有傳送訊號的許可權.

若程序有傳送訊號到 pid 指定的任何一個程序的許可權則呼叫成功,

否則呼叫失敗,沒有訊號發出.

返回值:呼叫成功則返回 0,否則返回-1.

例子:假設前一個例子程序號為 324,現向它發一個 SIGINT 訊號,讓它做

訊號處理:

kill((pid_t)324,SIGINT);

2.12.alarm()

設定一個程序的超時時鐘

功能:設定一個程序的超時時鐘.

語法:

#include <unistd.h<

unsigned int alarm(sec)

unsigned int sec;

說明:指示呼叫程序的超時時鐘在指定的時間後向呼叫程序傳送一個

SIGALRM 訊號.設定超時時鐘時時間值不會被放入堆疊中,後一次

設定會把前一次(還未到超時時間)沖掉.

若 sec 為 0,則取消任何以前設定的超時時鐘.

fork()會將新程序的超時時鐘初始化為 0.而當一個程序用 exec()

族系統呼叫新的執行檔案時,呼叫前設定的超時時鐘在呼叫後仍

有效.

返回值:返回上次設定超時時鐘後到呼叫時還剩餘的時間秒數.

例子:int flag=0;

void myself()

{

flag=1;

printf("get signal SIGALRM\n");

/*若要重新設定 SIGALRM 訊號中斷處理函式為本函式則執行

*以下步驟*/

void (*a)();

a=myself;

signal(SIGALRM,a);

flag=2;

}

main()

{

alarm(100); /*100 秒後發超時中斷訊號*/

while (1) {

sleep(2000); /*等待中斷訊號*/

if (flag==1) {

printf("skip system call sleep\n");

exit(0);

}

if (flag==2) {

printf("skip system call sleep\n");

printf("waiting for next signal\n");

}

}

}

2.13.msgsnd() 傳送訊息到指定的訊息佇列中

功能:傳送訊息到指定的訊息佇列中.

語法:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgsnd(msqid,msgp,msgsz,msgflg)

int msqid;

void *msgp;

size_t msgsz;

int msgflg;

說明:傳送一個訊息到由 msqid 指定訊息佇列標識號的訊息佇列.

引數 msgp 指向一個使用者定義的緩衝區,並且緩衝區的第一個域應

為長整型,指定訊息型別,其他資料放在緩衝區的訊息中其他正文

區內.下面是訊息元素定義:

long mtype;

char mtext[];

mtype 是一個整數,用於接收程序選擇訊息型別.

mtext 是一個長度為 msgsz 位元組的任何正文,引數 msgsz 可從 0 到系

統允許的最大值間變化.

msgflg 指定操作行為:

. 若(msgflg&IPC_NOWAIT)是真的,訊息並不是被立即傳送而呼叫

程序會立即返回.

. 若(msgflg&IPC_NOWAIT)不是真的,則呼叫程序會被掛起直到下

面情況之一發生:

* 訊息被髮送出去.

* 訊息佇列標誌被系統刪除.系統呼叫返回-1.

* 呼叫程序接收到一個未被忽略的中斷訊號,呼叫程序繼續

執行或被終止.

呼叫成功後,對應指定的訊息佇列的相關結構做如下動作:

. 訊息數(msg_qnum)加 1.

. 訊息佇列最近傳送程序號(msg_lspid)改為呼叫程序號.

. 訊息佇列傳送時間(msg_stime)改為當前系統時間.

以上資訊可用命令 ipcs -a 看到.

返回值:成功則返回 0,否則返回-1.

2.14.msgrcv() 從訊息佇列中取得指定型別的訊息

功能:從訊息佇列中取得指定型別的訊息.

語法:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgrcv(msqid,msgp,msgsz,msgtyp,msgflg)

int msqid;

void *msgp;

int msgsz;

long msgtyp;

int msgflg;

說明:本系統呼叫從由 msqid 指定的訊息佇列中讀取一個由 msgtyp 指定

型別的訊息到由 msgp 指向的緩衝區中,同樣的,該緩衝區的結構如

前所述,包括訊息型別和訊息正文.msgsz 為可接收的訊息正文的

位元組數.若接收到的訊息正文的長度大於 msgsz,則會被截短到

msgsz 位元組為止(當訊息標誌 msgflg&MSG_NOERROR 為真時),截掉的

部份將被丟失,而且不通知訊息傳送程序.

msgtyp 指定訊息型別:

. 為 0 則接收訊息佇列中第一個訊息.

. 大於 0 則接收訊息佇列中第一個型別為 msgtyp 的訊息.

. 小於 0 則接收訊息佇列中第一個型別值不小於 msgtyp 絕對值且

型別值又最小的訊息.

msgflg 指定操作行為:

. 若(msgflg&IPC_NOWAIT)是真的,呼叫程序會立即返回,若沒有

接收到訊息則返回值為-1,errno 設定為 ENOMSG.

. 若(msgflg&IPC_NOWAIT)不是真的,則呼叫程序會被掛起直到下

面情況之一發生:

* 佇列中的訊息的型別是有效的.

* 訊息佇列標誌被系統刪除.系統呼叫返回-1.

* 呼叫程序接收到一個未被忽略的中斷訊號,呼叫程序繼續

執行或被終止.

呼叫成功後,對應指定的訊息佇列的相關結構做如下動作:

. 訊息數(msg_qnum)減 1.

. 訊息佇列最近接收程序號(msg_lrpid)改為呼叫程序號.

. 訊息佇列接收時間(msg_rtime)改為當前系統時間.

以上資訊可用命令 ipcs -a 看到.

返回值:呼叫成功則返回值等於接收到實際訊息正文的位元組數.

不成功則返回-1.

2.15.msgctl()

訊息控制操作

功能:訊息控制操作

語法:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgctl(msqid,cmd,buf)

int msqid,cmd;

struct msqid_ds *buf;

說明:本系統呼叫提供一系列訊息控制操作,操作動作由 cmd 定義,以下

cmd 定義值表明了各操作動作的定義.

. IPC_STAT:將 msqid 相關的資料結構中各個元素的當前值放入由

buf 指向的結構中.

. IPC_SET:將 msqid 相關的資料結構中的下列元素設定為由 buf 指

向的結構中的對應值.

msg_perm.uid

msg_perm.gid

msg_perm.mode

msg_qbytes

本命令只能由有效 UID 等於 msg_perm.cuid 或 msg_perm.uid 的

程序或有效 UID 有合適許可權的程序操作.只有具有合適許可權的

使用者才能增加 msg_qbytes 的值.

. IPC_RMID:刪除由 msqid 指示的訊息佇列.將它從系統中刪除並

破壞相關的資料結構.

本命令只能由有效 UID 等於 msg_perm.cuid 或 msg_perm.uid 的

程序或有效 UID 有合適許可權的程序操作.

返回值:呼叫成功則返回值為 0,否則為-1.

2.16.msgget()

取得一個訊息佇列

功能:取得一個訊息佇列.

語法:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgget(key,msgflg)

key_t key;

int msgflg;

說明:本系統呼叫返回與引數 key 相關的訊息佇列的識別符號.

若以下事實成立,則與訊息佇列相關的識別符號和資料結構將被創

建出來:

. 若引數 key 等於 IPC_PRIVATE.

. 若引數 key 沒有一個已存在的訊息佇列識別符號與之相關,同時值

(msgflg&IPC_CREAT)為真.

建立訊息佇列時,與新的訊息佇列識別符號相關的資料結構將被初

始化為如下:

. msg_perm.cuid 和 msg_perm.uid 設定為呼叫程序的有效 UID.

. msg_perm.cgid 和 msg_perm.gid 設定為呼叫程序的有效 GID.

. msg_perm.mode 訪問許可權位元位設定為 msgflg 訪問許可權位元位.

. msg_qnum,msg_lspid,msg_lrpid,msg_stime,msg_rtime 設定為 0.

. msg_ctime 設定為當前系統時間.

. msg_qbytes 設定為系統允許的最大值.

返回值:呼叫成功則返回一非 0 值,稱為訊息佇列識別符號;否則返回值為-1.

例子:本例將包括上述所有訊息佇列操作的系統呼叫:

#define RKEY 0x9001L /*讀訊息佇列的 KEY 值*/

#define WKEY 0x9002L /*寫訊息佇列的 KEY 值*/

#define MSGFLG 0666 /*訊息佇列訪問許可權*/

#define IPC_WAIT 0 /*等待方式在 include 檔案中未定義*/

int rmsqid; /*讀訊息佇列識別符號*/

int wmsqid; /*寫訊息佇列識別符號*/

struct msgbuf {

long mtype;

char mtext[200];

} buf;

/*若讀訊息佇列已存在就取得識別符號,否則則建立並取得識別符號*/

if ((rmsqid=msgget(RKEY,MSGFLG|IPC_CREAT))<0) {

printf("get read message queue failed\n");

exit(1);

} /*若寫訊息佇列已存在則失敗,若不存在則建立並取得識別符號*/

if ((wmsqid="msgget(WKEY," MSGFLG|IPC_CREAT|IPC_TRUNC))<0) {

printf("get write message queue failed\n");

exit(2);

} /*接收所有型別的訊息*/

if (msgrcv(rmsqid,&buf,sizeof(struct msgbuf)-sizeof(long), 0L,IPC_WAIT)>0)

printf("get %ld type message from queue:%s\n",

buf.mtype,buf.mtext);

else {

printf("get message failed\n");

exit(3);

}

buf.mtype=3L;

if (msgsnd(wmsqid,&buf,sizeof(struct msgbuf)-sizeof(long),

IPC_NOWAIT)>0)

printf("send message OK\n");

else {

printf("send message failed\n");

exit(4);

相關推薦

LinuxLinux 程序程式設計

一.多程序程式的特點    程序是一個具有獨立功能的程式關於某個資料集合的一次可以併發執行的執行活動,是處 於活動狀態的計算機程式。    程序作為構成系統的基本細胞, 不僅是系統內部獨立執行的實體, 而且是獨立競爭資源的基本實體。    程序

linux 程序程式設計

1.建立程序fork() 1.1標頭檔案 #include<unistd.h> #include<sys/types.h> 1.2函式原型 pid_t fork( void); pid_t 是一個巨集定義,其實質是int 被定義在#i

python中程序程式設計

由於個人知識面有限,以下就說說我對python中多程序程式設計的理解,如果有錯誤的地方,請多多指教。 在python中有三種方式建立多程序:fork,process,pool 一: fork應用 import os import time print(

Linux程序程式設計小例——獲取網絡卡的IP地址

Linux下多程序程式設計的核心是呼叫fork()系統呼叫用來建立一個新的程序:pid_t   fork(void);  由fork()建立的新程序被稱為子程序。fork()函式被呼叫一次,但有兩次返回。 返回值=0:  子程序              返回值>0: 

C/S模式---程序程式設計

在單程序下進行socket的程式設計,伺服器通過accept()獲取到客戶端的檔案描述符,並且與該客戶端進行互動。但是實際有兩方面的因素都促使伺服器應該能夠同時與多個客戶端進行互動。 1.listen()函式將已經完成三次握手和即將完成三次握手的客戶端檔案描述符存放到佇列中。 2.在

Linux/Unix環境的make命令

無論是在Linux還是在Unix環境中,make都是一個非常重要的編譯命令。  Makefile檔案   Make工具最主要也是最基本的功能就是通過makefile檔案來描述源程式之間的相互關係並自動維護編譯工作。而makefile 檔案需要按照某種語法進行編寫,檔案中需要說

SpringSpring MVC原理及配置

進行 return sub sca scrip uil 線程安全 松耦合 必須 1.Spring MVC概述: Spring MVC是Spring提供的一個強大而靈活的web框架。借助於註解,Spring MVC提供了幾乎是POJO的開發模式,使得控制器的開發和測試更加簡

C語言文件操作

pri void rfi 識別 archive format 隨機 stat 文本文 轉自:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551780.html C語言中沒有輸入輸出語句,所有的輸入輸出功能都用

AndroidAndroid六種布局

spec rec 默認 bottom ron ado 居中 右下角 控制 這篇就對LinearLayout、RelativeLayout、自定義ViewGroup、FrameLayout、TableLayout、AbsoluteLayout六種布局進行詳細的講解。 1

C++拷貝構造函數

簡單的 之間 其他 創建 變量 tac 動態分配空間 data 產生 一. 什麽是拷貝構造函數 首先對於普通類型的對象來說,它們之間的復制是很簡單的,例如: int a = 100; int b = a; 而類對象與普通對象不同,類對象內部結構一般較為復雜,

轉載 c++中static的用法

ostream 並不會 style 轉載 程序員 都是 note 每次 reference 出處: http://blog.csdn.net/majianfei1023/article/details/45290467 C 語言的 static 關鍵字有三種(具體來說是

轉載Maven依賴中的scope

lan 無需 而已 ref targe 周期 包含 配置 com Maven的一個哲學是慣例優於配置(Convention Over Configuration), Maven默認的依賴配置項中,scope的默認值是compile,項目中經常傻傻的分不清,直接默認了。今天梳

java的動態代理機制

bar 同時 @override returns 復制 exce ins com hello 在學習Spring的時候,我們知道Spring主要有兩大思想,一個是IoC,另一個就是AOP,對於IoC,依賴註入就不用多說了,而對於Spring的核心AOP來說,我們不但要知道怎

Pythonhasattr() getattr() setattr() 使用方法

att err value ror 綜合 設置 pytho clas rec 本文轉自 https://www.cnblogs.com/cenyu/p/5713686.html hasattr(object, name)判斷一個對象裏面是否有name屬性或者name方法,返

Oracle 11g Dataguard 參數

異步模式 正常 10g enable ffi sys 過程 tnsnames async 轉自:https://www.jb51.net/article/52269.htm 這篇文章主要介紹了Oracle 11g Dataguard參數詳解,包含了獨立參數、主庫參數、備

TestNGTestNG併發執行用例和範例

前言 TestNG有多種併發方式支援,方法的併發,class級的併發,test級的併發等; 根據實際應用可以靈活的配置和使用,下面分別對幾種併發方法進行說明: 一、方法級併發 方法級併發即method級併發,此種併發方式需要將xml中的suite標籤的parallel屬性設定為m

TestNGTestNG用例執行方法

一、直接在eclipse內部執行 這種方式比較簡單,就是直接右鍵一個test檔案然後選擇以testNG執行,或者選擇xml檔案執行,基本執行方法見帖子:https://mp.csdn.net/mdeditor/83243822# 二、命令列方式 除了直接再eclipse內部執行外

NLPYou May Not Need Attention

廢話: 之前蹭上了BERT的熱度,粉以個位數每天的速度增長,感謝同學們的厚愛!弄得我上週本來打算寫文字分類,寫了兩筆又放下了,畢竟文字分類有很多SOTA模型,而我的研究還不夠深入。。慢慢完善吧,今天看到一篇You may not need attention,寫attention起家的我怎麼能放過,立刻打印出

轉載BlockingQueue(阻塞佇列)

注意:該隨筆內容完全引自http://wsmajunfeng.iteye.com/blog/1629354,寫的很好,非常感謝,複製過來算是個積累,怕以後找不到。 一. 前言   在新增的Concurrent包中,BlockingQueue很好的解決了多執行緒中,如何高效安全“傳輸”資

5Django專案配置settings.py

夫唯不爭,故天下莫能與之爭 ——老子《道德經》 本節內容 1.專案配置檔案settings.py介紹 2.資料庫配置【MySQL】 3.建立模型物件並和資料庫同步 4.python官方提供的專案後臺管理平臺的使用 注意:本節內容我們會按照三部分進行分步講解 我們建立好了一個Pyth