青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

<2009年2月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
1234567

統(tǒng)計

  • 隨筆 - 44
  • 文章 - 0
  • 評論 - 86
  • 引用 - 0

常用鏈接

留言簿(6)

隨筆分類(31)

隨筆檔案(44)

Mining

最新隨筆

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

Linux下C編程 進程通信 (IPC)

在Linux中存在下面幾種進程間通信方式:

1.POSIX無名信號量
2.System V信號量
3.System V消息隊列
4.System V共享內(nèi)存
5.管道(FIFO)

--------------------------------------------------------------------------------
1。POSIX無名信號量
如果你學習過操作系統(tǒng),那么肯定熟悉PV操作了.PV操作是原子操作.也就是操作是不可以中斷的,在一定的時間內(nèi),只能夠有一個進程的代碼在CPU上面執(zhí)行.在系統(tǒng)當中,有時候為了順利的使用和保護共享資源,大家提出了信號的概念. 假設我們要使用一臺打印機, 如果在同一時刻有兩個進程在向打印機輸出,那么最終的結(jié)果會是什么呢.為了處理這種情況,POSIX標準提出了有名信號量和無名信號量的概念,由于 Linux只實現(xiàn)了無名信號量,我們在這里就只是介紹無名信號量了. 信號量的使用主要是用來保護共享資源,使的資源在一個時刻只有一個進程所擁有.為此我們可以使用一個信號燈.當信號燈的值為某個值的時候,就表明此時資源不可以使用.否則就表>示可以使用. 為了提供效率,系統(tǒng)提供了下面幾個函數(shù)?
POSIX的無名信號量的函數(shù)有以下幾個:

int ?sem_init(sem_t? * sem, int ?pshared,unsigned? int ?value);
int ?sem_destroy(sem_t? * sem);
int ?sem_wait(sem_t? * sem);
int ?sem_trywait(sem_t? * sem);
int ?sem_post(sem_t? * sem);
int ?sem_getvalue(sem_t? * sem);

sem_init創(chuàng)建一個信號燈,并初始化其值為value.pshared決定了信號量能否在幾個進程間共享.由于目前Linux還沒有實現(xiàn)進程間共享信號燈,所以這個值只能夠取0.
sem_destroy是用來刪除信號燈的.
sem_wait調(diào)用將阻塞進程,直到信號燈的值大于0.這個函數(shù)返回的時候自動的將信號燈的值的件一.
sem_post和sem_wait相反,是將信號燈的內(nèi)容加一同時發(fā)出信號喚醒等待的進程..
sem_trywait和sem_wait相同,不過不阻塞的,當信號燈的值為0的時候返回EAGAIN,表示以后重試.
sem_getvalue得到信號燈的值.
由于Linux不支持,我們沒有辦法用源程序解釋了.


2。System V信號量
信號燈的主要用途是保護臨界資源(在一個時刻只被一個進程所擁有). System V信號量的函數(shù)主要有下面幾個.

key_t?ftok( char ? * pathname, char ?proj);
int ?semget(key_t?key, int ?nsems, int ?semflg);
int ?semctl( int ?semid, int ?semnum, int ?cmd,union?semun?arg);
int ?semop( int ?semid, struct ?sembuf? * spos, int ?nspos);

struct ?sembuf{
short ?sem_num;? /* ?使用那一個信號? */
short ?sem_op;? /* ?進行什么操作? */
short ?sem_flg;? /* ?操作的標志? */
};

ftok函數(shù)是根據(jù)pathname和proj來創(chuàng)建一個關鍵字.
semget創(chuàng)建一個信號量.成功時返回信號的ID,key是一個關鍵字,可以是用ftok創(chuàng)建的也可以是IPC_PRIVATE表明由系統(tǒng)選用一個關鍵字. nsems表明我們創(chuàng)建的信號個數(shù).semflg是創(chuàng)建的權(quán)限標志,和我們創(chuàng)建一個文件的標志相同.
semctl對信號量進行一系列的控制.semid是要操作的信號標志,semnum是信號的個數(shù),cmd是操作的命令.經(jīng)常用的兩個值是:SETVAL(設置信號量的值)和IPC_RMID(刪除信號燈).arg是一個給cmd的參數(shù).
semop是對信號進行操作的函數(shù).semid是信號標志,spos是一個操作數(shù)組表明要進行什么操作,nspos表明數(shù)組的個數(shù). 如果 sem_op大于0,那么操作將sem_op加入到信號量的值中,并喚醒等待信號增加的進程. 如果為0,當信號量的值是0的時候,函數(shù)返回,否則阻塞直到信號量的值為0. 如果小于0,函數(shù)判斷信號量的值加上這個負值.如果結(jié)果為0喚醒等待信號量為0的進程,如果小與0函數(shù)阻塞.如果大于0,那么從信號量里面減去這個值并返回.

下面我們一以一個實例來說明這幾個函數(shù)的使用方法.

#define ?PERMS?S_IRUSR|S_IWUSR
void ?init_semaphore_struct( struct ?sembuf? * sem, int ?semnum, int ?semop, int ?semflg)
{
?
/* ?初始話信號燈結(jié)構(gòu)? */
?sem
-> sem_num = semnum;
?sem
-> sem_op = semop;
?sem
-> sem_flg = semflg;
}
int ?del_semaphore( int ?semid)
{
?
/* ?信號燈并不隨程序的結(jié)束而被刪除,如果我們沒刪除的話(將1改為0)
?可以用ipcs命令查看到信號燈,用ipcrm可以刪除信號燈的
?
*/
?
#if ?1
?
return ?semctl(semid, 0 ,IPC_RMID);
?
#endif
}

int ?main( int ?argc, char ? ** argv)
{
?
char ?buffer[MAX_CANON], * c;
?
int ?i,n;
?
int ?semid,semop_ret,status;
?pid_t?childpid;
?
struct ?sembuf?semwait,semsignal;

?
if ((argc != 2 ) || ((n = atoi(argv[ 1 ])) < 1 ))
?{
??fprintf(stderr,
" Usage:%s?number\n\a " ,argv[ 0 ]);
??exit(
1 );
?}
?
?
/* ?使用IPC_PRIVATE?表示由系統(tǒng)選擇一個關鍵字來創(chuàng)建?? */
?
/* ?創(chuàng)建以后信號燈的初始值為0? */
?
if ((semid = semget(IPC_PRIVATE, 1 ,PERMS)) ==- 1 )
?{
??fprintf(stderr,
" [%d]:Acess?Semaphore?Error:%s\n\a " ,
??getpid(),strerror(errno));
??exit(
1 );
?}

?
/* ?semwait是要求資源的操作(-1)? */
?init_semaphore_struct(
& semwait, 0 , - 1 , 0 );

?
/* ?semsignal是釋放資源的操作(+1)? */
?init_semaphore_struct(
& semsignal, 0 , 1 , 0 );

?
/* ?開始的時候有一個系統(tǒng)資源(一個標準錯誤輸出)? */
?
if (semop(semid, & semsignal, 1 ) ==- 1 )
?{
??fprintf(stderr,
" [%d]:Increment?Semaphore?Error:%s\n\a " ,?getpid(),?strerror(errno));
??
if (del_semaphore(semid) ==- 1 )
???fprintf(stderr,
" [%d]:Destroy?Semaphore?Error:%s\n\a " ,?getpid(),?strerror(errno));
??exit(
1 );
?}

?
/* ?創(chuàng)建一個進程鏈? */
?
for (i = 0 ;i < n;i ++ )
??
if (childpid = fork())? break ;

?sprintf(buffer,
" [i=%d]-->[Process=%d]-->[Parent=%d]-->[Child=%d]\n " ,?i,getpid(),getppid(),childpid);
?c
= buffer;

?
/* ?這里要求資源,進入原子操作? */
?
while (((semop_ret = semop(semid, & semwait, 1 )) ==- 1 ) && (errno == EINTR));
?
if (semop_ret ==- 1 )
?{
??fprintf(stderr,
" [%d]:Decrement?Semaphore?Error:%s\n\a " ,
??getpid(),strerror(errno));
?}
?
else
?{
??
while ( * c != ' \0 ' )fputc( * c ++ ,stderr);
??
/* ?原子操作完成,趕快釋放資源? */
??
while (((semop_ret = semop(semid, & semsignal, 1 )) ==- 1 ) && (errno == EINTR));
??
if (semop_ret ==- 1 )
???fprintf(stderr,
" [%d]:Increment?Semaphore?Error:%s\n\a " ,?getpid(),strerror(errno));
?}

?
/* ?不能夠在其他進程反問信號燈的時候,我們刪除了信號燈? */
?
while ((wait( & status) ==- 1 ) && (errno == EINTR));
?
/* ?信號燈只能夠被刪除一次的? */
?
if (i == 1 )
??
if (del_semaphore(semid) ==- 1 )
?fprintf(stderr,
" [%d]:Destroy?Semaphore?Error:%s\n\a " ,?getpid(),strerror(errno));
?exit(
0 );
}


3。SystemV消息隊列
為了便于進程之間通信,我們可以使用管道通信 SystemV也提供了一些函數(shù)來實現(xiàn)進程的通信.這就是消息隊列.

int ?msgget(key_t?key, int ?msgflg);
int ?msgsnd( int ?msgid, struct ?msgbuf? * msgp, int ?msgsz, int ?msgflg);
int ?msgrcv( int ?msgid, struct ?msgbuf? * msgp, int ?msgsz,
long ?msgtype, int ?msgflg);
int ?msgctl(Int?msgid, int ?cmd, struct ?msqid_ds? * buf);

struct ?msgbuf?{
long ?msgtype;??? /* ?消息類型? */
.?
/* ?其他數(shù)據(jù)類型? */
}

msgget函數(shù)和semget一樣,返回一個消息隊列的標志.
msgctl和semctl是對消息進行控制.
msgsnd和msgrcv函數(shù)是用來進行消息通訊的.msgid是接受或者發(fā)送的消息隊列標志. msgp是接受或者發(fā)送的內(nèi)容.msgsz是消息的大小. 結(jié)構(gòu)msgbuf包含的內(nèi)容是至少有一個為msgtype.其他的成分是用戶定義的.對于發(fā)送函數(shù)msgflg指出緩沖區(qū)用完時候的操作.接受函數(shù)指出無消息時候的處理.一般為 0. 接收函數(shù)msgtype指出接收消息時候的操作.
如果msgtype=0,接收消息隊列的第一個消息.大于0接收隊列中消息類型等于這個值的第一個消息.小于0接收消息隊列中小于或者等于 msgtype絕對值的所有消息中的最小一個消息. 我們以一個實例來解釋進程通信.下面這個程序有server和client組成.先運行服務端后運行客戶端.

服務端 server.c

#define ???MSG_FILE?"server.c"
#define ???BUFFER?255
#define ???PERM?S_IRUSR|S_IWUSR

struct ?msgtype?{
long ?mtype;
char ?buffer[BUFFER + 1 ];
};

int ?main()
{
????
struct ?msgtype?msg;
????key_t?key;
????
int ?msgid;

????
if ((key = ftok(MSG_FILE, ' a ' )) ==- 1 )
????{
????????fprintf(stderr,
" Creat?Key?Error:%s\a\n " ,strerror(errno));
????????exit(
1 );
????}

????
if ((msgid = msgget(key,PERM | IPC_CREAT | IPC_EXCL)) ==- 1 )
????{
????????fprintf(stderr,
" Creat?Message??Error:%s\a\n " ,strerror(errno));
????????exit(
1 );
????}

????
while ( 1 )
????{
????????msgrcv(msgid,
& msg, sizeof ( struct ?msgtype), 1 , 0 );
????????fprintf(stderr,
" Server?Receive:%s\n " ,msg.buffer);
????????msg.mtype
= 2 ;
????????msgsnd(msgid,
& msg, sizeof ( struct ?msgtype), 0 );
????}
????exit(
0 );
}


--------------------------------------------------------------------------------

客戶端(client.c)

#define ???MSG_FILE?"server.c"
#define ???BUFFER?255
#define ???PERM?S_IRUSR|S_IWUSR

struct ?msgtype?{
long ?mtype;
char ?buffer[BUFFER + 1 ];
};

int ?main( int ?argc, char ? ** argv)
{
?
struct ?msgtype?msg;
?key_t?key;
?
int ?msgid;

?
if (argc != 2 )
?{
??fprintf(stderr,
" Usage:%s?string\n\a " ,argv[ 0 ]);
??exit(
1 );
?}

?
if ((key = ftok(MSG_FILE, ' a ' )) ==- 1 )
?{
??fprintf(stderr,
" Creat?Key?Error:%s\a\n " ,strerror(errno));
??exit(
1 );
?}

?
if ((msgid = msgget(key,PERM)) ==- 1 )
?{
??fprintf(stderr,
" Creat?Message??Error:%s\a\n " ,strerror(errno));
??exit(
1 );
?}

?msg.mtype
= 1 ;
?strncpy(msg.buffer,argv[
1 ],BUFFER);
?msgsnd(msgid,
& msg, sizeof ( struct ?msgtype), 0 );?
?memset(
& msg, ' \0 ' , sizeof ( struct ?msgtype));
?msgrcv(msgid,
& msg, sizeof ( struct ?msgtype), 2 , 0 );
?fprintf(stderr,
" Client?receive:%s\n " ,msg.buffer);
?exit(
0 );
}??

注意服務端創(chuàng)建的消息隊列最后沒有刪除,我們要使用ipcrm命令來刪除的.
4。SystemV共享內(nèi)存
還有一個進程通信的方法是使用共享內(nèi)存.SystemV提供了以下幾個函數(shù)以實現(xiàn)共享內(nèi)存.

int ?shmget(key_t?key, int ?size, int ?shmflg);
void ? * shmat( int ?shmid, const ? void ? * shmaddr, int ?shmflg);
int ?shmdt( const ? void ? * shmaddr);
int ?shmctl( int ?shmid, int ?cmd, struct ?shmid_ds? * buf);

shmget和shmctl沒有什么好解釋的.size是共享內(nèi)存的大小.
shmat是用來連接共享內(nèi)存的.shmdt是用來斷開共享內(nèi)存的.
shmaddr,shmflg我們只要用0代替就可以了.在使用一個共享內(nèi)存之前我們調(diào)用 shmat得到共享內(nèi)存的開始地址,使用結(jié)束以后我們使用shmdt斷開這個內(nèi)存.?

#define ?PERM?S_IRUSR|S_IWUSR
int ?main( int ?argc, char ? ** argv)
{
?
?
int ?shmid;
?
char ? * p_addr, * c_addr;
?
if (argc != 2 )
?{
??fprintf(stderr,
" Usage:%s\n\a " ,argv[ 0 ]);
??exit(
1 );
?}

?
if ((shmid = shmget(IPC_PRIVATE, 1024 ,PERM)) ==- 1 )
?{
??fprintf(stderr,
" Create?Share?Memory?Error:%s\n\a " ,strerror(errno));
??exit(
1 );
?}
?
if (fork())
?{
??p_addr
= shmat(shmid, 0 , 0 );
??memset(p_addr,
' \0 ' , 1024 );
??strncpy(p_addr,argv[
1 ], 1024 );
??exit(
0 );
?}
?
else
?{
??c_addr
= shmat(shmid, 0 , 0 );
??printf(
" Client?get?%s " ,c_addr);
??exit(
0 );
?}?
}?

這個程序是父進程將參數(shù)寫入到共享內(nèi)存,然后子進程把內(nèi)容讀出來.最后我們要使用ipcrm釋放資源的.先用ipcs找出ID然后用ipcrm shm ID刪除.?

5、管道(FIFO)
管道有無名管道和有名管道兩種,無名管道一般在父子進程中使用。
無名管道的使用方法一般是:
#include?<unistd.h>
int?pipe(int?filedes[2]);
filedes[
0]用于讀出數(shù)據(jù),讀取時必須關閉寫入端,即close(filedes[1]);
filedes[
1]用于寫入數(shù)據(jù),寫入時必須關閉讀取端,即close(filedes[0])。

無名管道的使用方法是:
#include?<sys/types.h>
#include?
<sys/stat.h>
int?mkfifo(const?char?*pathname,?mode_t?mode);

讀寫管道與讀寫文件的操作相同。



posted on 2006-08-04 18:05 泡泡牛 閱讀(3444) 評論(1)  編輯 收藏 引用

評論

# re: Linux下C編程 進程通信 (IPC) 2009-03-04 11:18 fuck

你的代碼有錯誤!
ipc 信號量的代碼里,應該是i=0時才能刪除sem資源
  回復  更多評論    

只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            午夜精品久久| 久久精品二区三区| 欧美婷婷久久| 欧美激情一区| 欧美午夜无遮挡| 国产精品video| 国产精品看片你懂得| 国产精品免费小视频| 国产精品一区二区在线观看网站 | 午夜精品美女久久久久av福利| 日韩亚洲欧美综合| 亚洲一区二区三区激情| 亚洲欧美电影院| 久久久综合免费视频| 亚洲福利视频三区| 亚洲国产你懂的| 中文日韩欧美| 久久精品2019中文字幕| 欧美69视频| 国产精品美女主播| 在线精品国精品国产尤物884a| 日韩亚洲欧美在线观看| 免费在线国产精品| 亚洲精品中文在线| 国产有码在线一区二区视频| 亚洲国产高清自拍| 亚洲视频中文字幕| 欧美xx69| 亚洲欧美一区二区三区在线| 麻豆freexxxx性91精品| 国产精品欧美日韩久久| 亚洲国产精品久久精品怡红院| 亚洲午夜伦理| 免费观看亚洲视频大全| 亚洲视频中文| 欧美激情国产日韩| 国产一区二区久久久| 亚洲视频导航| 亚洲精品美女在线观看| 久久亚洲一区二区| 国产日产亚洲精品系列| 99日韩精品| 亚洲电影免费| 久久精品卡一| 国产婷婷色一区二区三区在线| 在线亚洲电影| 亚洲清纯自拍| 可以看av的网站久久看| 国内精品一区二区三区| 久久se精品一区精品二区| 99精品免费| 欧美日韩免费一区二区三区视频| 亚洲福利久久| 美女精品在线观看| 久久精品国产99| 国产区亚洲区欧美区| 亚洲欧美日本国产有色| 日韩一级欧洲| 欧美日韩国产黄| 99精品免费视频| 最新国产成人在线观看| 欧美成人国产一区二区| 在线日韩中文字幕| 美女视频网站黄色亚洲| 久久国产乱子精品免费女| 国产亚洲精品aa| 久久精品论坛| 久久婷婷综合激情| 美女性感视频久久久| 欧美激情国产高清| 噜噜噜躁狠狠躁狠狠精品视频| 激情综合中文娱乐网| 久久嫩草精品久久久久| 午夜精品免费在线| 国内久久精品视频| 免费精品99久久国产综合精品| 久久免费观看视频| 亚洲免费激情| 亚洲一区二区三区三| 国产日韩1区| 免费影视亚洲| 亚洲国产精品成人综合| 亚洲国产午夜| 亚洲激情网站| 欧美日韩一区二区三区在线观看免| 亚洲精品无人区| 一区二区三区四区蜜桃| 国产亚洲欧美日韩美女| 欧美成年人网站| 欧美午夜精品久久久久免费视| 欧美一区二区三区日韩| 久久免费偷拍视频| 在线视频一区观看| 久久gogo国模啪啪人体图| 最新国产成人av网站网址麻豆| 亚洲精品中文字幕女同| 国产亚洲亚洲| 日韩视频不卡中文| 国产一区二区主播在线| 亚洲激情av在线| 国产欧美日韩一区二区三区在线| 免费在线成人| 国产精品亚洲不卡a| 欧美激情1区2区| 国产麻豆日韩| 亚洲精品极品| 在线视频国产日韩| 亚洲欧美在线网| 一区二区三区四区五区视频| 久久久亚洲国产美女国产盗摄| 亚洲男人的天堂在线aⅴ视频| 狂野欧美一区| 久久精品欧美日韩| 国产精品国产亚洲精品看不卡15 | 麻豆免费精品视频| 欧美日韩三级| 欧美高清在线一区二区| 国产区精品在线观看| 亚洲日本乱码在线观看| 在线欧美电影| 久久国产精品黑丝| 性色一区二区三区| 欧美日韩亚洲不卡| 亚洲国产一区在线观看| 在线观看欧美激情| 久久成人国产| 久久激情视频久久| 国产精品亚洲а∨天堂免在线| 99精品热视频| 一本色道久久| 欧美激情一区二区三级高清视频| 可以免费看不卡的av网站| 国产精品日本欧美一区二区三区| 亚洲每日在线| 日韩午夜在线播放| 欧美精品日韩www.p站| 欧美国产日韩视频| 亚洲人被黑人高潮完整版| 久久综合999| 欧美高清在线| 99re66热这里只有精品4 | 国产一二精品视频| 欧美尤物巨大精品爽| 一区二区亚洲精品| 午夜亚洲福利| 久久精品国产亚洲5555| 国产一区视频网站| 久久狠狠久久综合桃花| 久久国产精品第一页| 国产私拍一区| 久久精品国产第一区二区三区最新章节 | 久久久999精品免费| 久久九九电影| 黑人极品videos精品欧美裸| 久久精品国产一区二区三区| 久久精品视频免费观看| 国内久久精品| 欧美福利精品| 一区二区日韩精品| 欧美尤物巨大精品爽| 韩日精品中文字幕| 欧美丰满高潮xxxx喷水动漫| 亚洲欧洲一区二区三区久久| 一本色道久久综合亚洲精品高清| 欧美日本一区二区三区| 亚洲在线视频| 可以看av的网站久久看| 日韩视频精品在线| 国产精品免费区二区三区观看| 亚洲欧美一区二区三区极速播放| 免费观看日韩av| 中文日韩欧美| 国产亚洲综合在线| 欧美国产91| 欧美在线观看网址综合| 亚洲国产影院| 欧美一级视频| 亚洲人成在线播放网站岛国| 国产精品九九| 欧美福利电影网| 欧美在线观看网站| 亚洲最新视频在线播放| 麻豆精品精华液| 欧美在线日韩精品| 一区二区成人精品| 国产在线精品自拍| 欧美日本高清一区| 久久精品一区二区| 亚洲视屏一区| 亚洲电影一级黄| 久久国产精品久久久久久电车| 亚洲国产导航| 榴莲视频成人在线观看| 亚洲欧美日韩精品久久| 亚洲美女黄网| 欧美黄色一级视频| 久久久噜久噜久久综合| 亚洲综合国产| 一本色道久久综合亚洲精品高清| 国内精品久久久久国产盗摄免费观看完整版|