?? 進程和線程編程.htm
字號:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0041)http://www.huihoo.com/joyfire.net/11.html -->
<HTML><HEAD><TITLE>進程和線程編程</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<META content="MSHTML 6.00.2900.2722" name=GENERATOR></HEAD>
<BODY style="FONT-SIZE: 9pt; FONT-FAMILY: 宋體">
<CENTER>
<TABLE cellSpacing=10 cellPadding=10 width="60%" bgColor=#ffb693>
<TBODY>
<TR>
<TD align=middle><FONT
size=+2><!--標題由此開始-->進程和線程編程</FONT></TD></TR></TBODY></TABLE></CENTER>
<P>
<H3>目 錄</H3><!--目錄由此開始--><A id=Content name=Content></A>
<OL>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I236">進程和線程編程</A>
<OL>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I237">原始管道</A>
<OL>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I238">pipe()</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I239">dup()</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I240">dup2()</A>
<LI><A
href="http://www.huihoo.com/joyfire.net/11.html#I241">popen()和pclose()</A>
</LI></OL>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I242">命名管道</A>
<OL>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I243">創(chuàng)建FIFO</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I244">操作FIFO</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I245">阻塞FIFO</A>
</LI></OL>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I246">消息隊列</A>
<OL>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I247">msgget()</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I248">msgsnd()</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I249">msgrcv()</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I250">msgctl()</A>
</LI></OL>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I251">信號量</A>
<OL>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I252">semget()</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I253">semop()</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I254">semctl()</A>
</LI></OL>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I255">共享內(nèi)存</A>
<OL>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I256">shmget()</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I257">shmat()</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I258">shmctl()</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I259">shmdt()</A>
</LI></OL>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I260">線程</A>
<OL>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I261">線程同步</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I262">使用信號量協(xié)調(diào)程序</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I263">代碼例子</A>
<OL>
<LI><A
href="http://www.huihoo.com/joyfire.net/11.html#I264">newthread</A>
<LI><A
href="http://www.huihoo.com/joyfire.net/11.html#I265">exitthead</A>
<LI><A
href="http://www.huihoo.com/joyfire.net/11.html#I266">getchannel</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I267">def</A>
<LI><A href="http://www.huihoo.com/joyfire.net/11.html#I268">release</A>
<LI><A
href="http://www.huihoo.com/joyfire.net/11.html#I269">redezvous</A>
<LI><A
href="http://www.huihoo.com/joyfire.net/11.html#I270">unbouded</A></LI></OL></LI></OL></LI></OL></LI></OL>
<HR>
<BR><A id=I236 name=I236></A>
<CENTER><B><FONT size=+2>進程和線程編程</FONT></B></CENTER><BR>
看一下UNIX系統(tǒng)中的進程和Mach的任務和線程之間的關系。在UNIX系統(tǒng)中,一個進程包括一個可執(zhí)行的程序和一系列的資源,例如文件描述符表和地址空間。在Mach中,一個任務僅包括一系列的資源;線程處理所有的可執(zhí)行代碼。一個Mach的任務可以有任意數(shù)目的線程和它相關,同時每個線程必須和某個任務相關。和某一個給定的任務相關的所有線程都共享任務的資源。這樣,一個線程就是一個程序計數(shù)器、一個堆棧和一系列的寄存器。所有需要使用的數(shù)據(jù)結構都屬于任務。一個UNIX系統(tǒng)中的進程在Mach中對應于一個任務和一個單獨的線程。<BR>
<CENTER><A
href="http://www.huihoo.com/joyfire.net/11.html#Content">[目錄]</A></CENTER>
<HR>
<BR><A id=I237 name=I237></A>
<CENTER><B><FONT size=+2>原始管道</FONT></B></CENTER><BR>
使用C語言創(chuàng)建管道要比在shell下使用管道復雜一些。如果要使用C語言創(chuàng)建一個簡單的管道,可以使用系統(tǒng)調(diào)用pipe()。它接受一個參數(shù),也就是一個包括兩個整數(shù)的數(shù)組。如果系統(tǒng)調(diào)用成功,此數(shù)組將包括管道使用的兩個文件描述符。創(chuàng)建一個管道之后,一般情況下進程將產(chǎn)生一個新的進程。
<P>
可以通過打開兩個管道來創(chuàng)建一個雙向的管道。但需要在子進程中正確地設置文件描述必須在系統(tǒng)調(diào)用fork()中調(diào)用pipe(),否則子進程將不會繼承文件描述符。當使用半雙工管道時,任何關聯(lián)的進程都必須共享一個相關的祖先進程。因為管道存在于系統(tǒng)內(nèi)核之中,所以任何不在創(chuàng)建管道的進程的祖先進程之中的進程都將無法尋址它。而在命名管道中卻不是這樣。<BR>
<CENTER><A
href="http://www.huihoo.com/joyfire.net/11.html#Content">[目錄]</A></CENTER>
<HR>
<BR><A id=I238 name=I238></A>
<CENTER><B><FONT
size=+2>pipe()</FONT></B></CENTER><BR>系統(tǒng)調(diào)用:pipe();<BR>原型:intpipe(intfd[2]);<BR>返回值:如果系統(tǒng)調(diào)用成功,返回0<BR>如果系統(tǒng)調(diào)用失敗返回-1:errno=EMFILE(沒有空閑的文件描述符)<BR>EMFILE(系統(tǒng)文件表已滿)<BR>EFAULT(fd數(shù)組無效)<BR>注意fd[0]用于讀取管道,fd[1]用于寫入管道。<BR>#include<stdio.h><BR>#include<unistd.h><BR>#include<sys/types.h><BR>main()<BR>{<BR>intfd[2];<BR>pipe(fd);<BR>..<BR>}<BR>一旦創(chuàng)建了管道,我們就可以創(chuàng)建一個新的子進程:<BR>#include<stdio.h><BR>#include<unistd.h><BR>#include<sys/types.h><BR>main()<BR>{<BR>intfd[2];<BR>pid_t
childpid;<BR>pipe(fd);<BR>if((childpid=fork())==-1)<BR>{<BR>perror("fork");<BR>exit(1);<BR>}..<BR>}
<P>
如果父進程希望從子進程中讀取數(shù)據(jù),那么它應該關閉fd1,同時子進程關閉fd0。反之,如果父進程希望向子進程中發(fā)送數(shù)據(jù),那么它應該關閉fd0,同時子進程關閉fd1。因為文件描述符是在父進程和子進程之間共享,所以我們要及時地關閉不需要的管道的那一端。單從技術的角度來說,如果管道的一端沒有正確地關閉的話,你將無法得到一個EOF。
<P>#include<stdio.h><BR>#include<unistd.h><BR>#include<sys/types.h><BR>main()<BR>{<BR>intfd[2];<BR>pid_t
childpid;<BR>pipe(fd);<BR>if((childpid=fork())==-1)<BR>{<BR>perror("fork");<BR>exit(1);<BR>}<BR>if(childpid==0)<BR>{<BR>/*Child
process closes up in put side of
pipe*/<BR>close(fd[0]);<BR>}<BR>else<BR>{<BR>/*Parent process closes up out put
side of pipe*/<BR>close(fd[1]);<BR>}..<BR>}
<P> 正如前面提到的,一但創(chuàng)建了管道之后,管道所使用的文件描述符就和正常文件的文件描述符一樣了。
<P>#include<stdio.h><BR>#include<unistd.h><BR>#include<sys/types.h><BR>intmain(void)<BR>{<BR>intfd[2],nbytes;<BR>pid_tchildpid;<BR>charstring[]="Hello,world!\n";<BR>charreadbuffer[80];<BR>pipe(fd);<BR>if((childpid=fork())==-1)<BR>{<BR>perror("fork");<BR>exit(1);<BR>}<BR>if(childpid==0)<BR>{<BR>/*Child
process closes up in put side of
pipe*/<BR>close(fd[0]);<BR>/*Send"string"through the out put side of
pipe*/<BR>write(fd[1],string,strlen(string));<BR>exit(0);<BR>}<BR>else<BR>{<BR>/*Parent
process closes up out put side of
pipe*/<BR>close(fd[1]);<BR>/*Readinastringfromthepipe*/<BR>nbytes=read(fd[0],readbuffer,sizeof(readbuffer));<BR>printf("Receivedstring:%s",readbuffer);<BR>}<BR>return(0);<BR>}
<P>
一般情況下,子進程中的文件描述符將會復制到標準的輸入和輸出中。這樣子進程可以使用exec()執(zhí)行另一個程序,此程序繼承了標準的數(shù)據(jù)流。
<P>
<P>
<P>
<CENTER><A
href="http://www.huihoo.com/joyfire.net/11.html#Content">[目錄]</A></CENTER>
<HR>
<BR><A id=I239 name=I239></A>
<CENTER><B><FONT
size=+2>dup()</FONT></B></CENTER><BR>系統(tǒng)調(diào)用:dup();<BR>原型:intdup(intoldfd);<BR>返回:如果系統(tǒng)調(diào)用成功,返回新的文件描述符<BR>如果系統(tǒng)調(diào)用失敗,返回-1:errno=EBADF(oldfd不是有效的文件描述符)<BR>EBADF(newfd超出范圍)<BR>EMFILE(進程的文件描述符太多)
<P>
注意舊文件描述符oldfd沒有關閉。雖然舊文件描述符和新創(chuàng)建的文件描述符可以交換使用,但一般情況下需要首先關閉一個。系統(tǒng)調(diào)用dup()使用的是號碼最小的空閑的文件描述符。
<P>再看下面的程序:<BR>..<BR>childpid=fork();<BR>if(childpid==0)<BR>{<BR>/*Close up
standard input of the child*/<BR>close(0);<BR>/*Dup licate the input side of
pipe to
stdin*/<BR>dup(fd[0]);<BR>execlp("sort","sort",NULL);<BR>.<BR>}<BR>
因為文件描述符0(stdin)被關閉,所以dup()把管道的輸入描述符復制到它的標準輸入中。這樣我們可以調(diào)用execlp(),使用sort程序覆蓋子進程的正文段。因為新創(chuàng)建的程序從它的父進程中繼承了標準輸入/輸出流,所以它實際上繼承了管道的輸入端作為它的標準輸入端。現(xiàn)在,最初的父進程送往管道的任何數(shù)據(jù)都將會直接送往sort函數(shù)。
<P>
<P>
<P>
<CENTER><A
href="http://www.huihoo.com/joyfire.net/11.html#Content">[目錄]</A></CENTER>
<HR>
<BR><A id=I240 name=I240></A>
<CENTER><B><FONT
size=+2>dup2()</FONT></B></CENTER><BR>系統(tǒng)調(diào)用:dup2();<BR>原型:intdup2(intoldfd,intnewfd);<BR>返回值:如果調(diào)用成功,返回新的文件描述符<BR>如果調(diào)用失敗,返回-1:errno=EBADF(oldfd不是有效的文件描述符)<BR>EBADF(newfd超出范圍)<BR>EMFILE(進程的文件描述符太多)<BR>注意dup2()將關閉舊文件描述符。
<P>
使用此系統(tǒng)調(diào)用,可以將close操作和文件描述符復制操作集成到一個系統(tǒng)調(diào)用中。另外,此系統(tǒng)調(diào)用保證了操作的自動進行,也就是說操作不能被其他的信號中斷。這個操作將會在返回系統(tǒng)內(nèi)核之前完成。如果使用前一個系統(tǒng)調(diào)用dup(),程序員不得不在此之前執(zhí)行一個close()操作。請看下面的程序:<BR>..
<P>childpid=fork();<BR>if(childpid==0)<BR>{<BR>/*Close stdin,dup licate the
input side of pipe to
stdin*/<BR>dup2(0,fd[0]);<BR>execlp("sort","sort",NULL);<BR>..<BR>}
<P>
<P>
<P>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -