版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、寫在前面的話。這是去年夏天剛來SOHU的時候?qū)懙?。在本版最初好像發(fā)過一遍?,F(xiàn)在整理個人文集,重發(fā)一遍。大家見諒。說明:本文所有程序,應(yīng)在UNIX類操作系統(tǒng)下編譯執(zhí)行。第一章:生成一個Process(進程)進程是什么?簡單地說,進程就是在執(zhí)行狀態(tài)下的一個程序(包括CPU狀態(tài),所占內(nèi)存的狀態(tài),等等)A進程生成了B進程,也就是說,A程序在執(zhí)行的時候,又生成了另一個進程B。這個時候,我們可以把A進程叫做父進程,把B進程叫做子進程。例程序:/ Usage : ./a.out 20#includeint main( int argc , char *argv)int dep_time;dep_time =
2、 atoi( argv1 )*60 ; /將參數(shù)中給出的20(分鐘)轉(zhuǎn)換成整型的秒數(shù)if( fork()=0 ) /生成子進程,然后父進程中止sleep( dep_time );fprintf( stderr , !n);return 0;上面的程序是一個鬧鐘程序。當(dāng)你執(zhí)行之后。程序不會顯示什么,而是一下就回到UNIX的提示符下。但是你在命令行中指定了20分鐘后你有事,那么在你執(zhí)行這個程序之后20分鐘,他會提醒你到時間了。本程序只是做示例用,沒有檢查參數(shù)是否正確,等等。生成一個新的進程,可以使用 fork() 函數(shù) 。以下說說fork()函數(shù)。頭文件: #include 形式 pid_t fo
3、rk();參數(shù) 無返回值 成功時: 父進程中:子進程的PID (Process ID)子進程中:0失敗時: 父進程中:-1由于失敗,沒有生成子進程;fork()剛執(zhí)行完的時候,子進程和父進程是完全一模一樣的兩份進程(當(dāng)然,PID是不一樣的)。他們的各個變量的值都是一樣的,而且都認為自己已經(jīng)執(zhí)行完fork()了。fork()后,區(qū)分父進程和子進程,只要看fork()的返回值就行了。if( fork()=0 ) printf(這是子進程);else printf(這是父進程);同理:if( fork()=0 )/接下來要子進程做的工作else/接下來要父進程做的工作一般,我們會把fork()返回給
4、父進程的值保存下來(其實就是子進程的PID),等到需要結(jié)束子進程的時候,我們關(guān)掉他,如下:pid_t child_pid ;child_pid=fork();if( child_pid=0 )/ . .else/ . ./ . .需要結(jié)束子進程的時候kill( child_pid , SIGKILL ) / kill()函數(shù)是用來發(fā)給另一個進程一個消息的。以后再講。先寫這些,試試手。喜歡就頂。要是沒人愛看我就不寫了。呵呵。省得大家說我亂貼垃圾。以后計劃貼的東西:在程序中執(zhí)行UNIX命令或者另一個程序取得環(huán)境變量并利用UNIX文件系統(tǒng)(在程序中取得分區(qū)信息,等等)使用管道操作達到在各進程互相交流
5、數(shù)據(jù)信號(signal)進程間共享內(nèi)存用message實現(xiàn)進程間共享信息本文所有程序均應(yīng)在UNIX系操作系統(tǒng)下編譯執(zhí)行。第二章:在程序中執(zhí)行UNIX命令或者其它程序在UNIX下,像DOS的那樣的程序,我們稱之為外殼(shell)。外殼就是一個命令解釋器,你在外殼的提示符下輸入命令(如同DOS的提示符一樣),系統(tǒng)便會執(zhí)行。DOS的提示符一般是C:,當(dāng)然,你想改成什么樣就能改成什么樣,又當(dāng)然,像BBS一樣貼張圖上去是不太現(xiàn)實的。UNIX的提示符根據(jù)外殼的不同是不同的。為了更好地說明本章想講解的內(nèi)容,我們先做一個外殼試試(玩具級別的)。我們給他起名叫SSH(Sohu Shell)吧。想取名叫CSH,
6、可惜CSH在沒生我之前就有了。呵呵。/* 簡單的外殼程序 */#includeint main()static char prompt64= ;char command256;int st;fprintf(stderr,%s,prompt); / 在屏幕上輸出提示符while(gets(command)!=NULL) / 取得命令if(fork()=0) / 生成子進程 / 這里是子進程接下來要做的事if( execl(command,command,(char *)0)=(-1) )/ 上一句是執(zhí)行命令 exit(1); / 當(dāng)出錯時子進程異常中止else / 父進程wait(&st); /
7、 等待子進程結(jié)束fprintf(stderr,%s,prompt);/ 輸出提示符,等待命令return 0;執(zhí)行方法:%./ssh/bin/ls當(dāng)前目錄下文件名一覽Ctrl+D%普通的外殼在執(zhí)行exit命令后會關(guān)閉。也就是說,退出一層外殼。咱們這個程序現(xiàn)在還做不到。愿意的話加上這個功能試試好了。所以要關(guān)閉這個外殼就得來點狠的。Ctrl+D,Ctrl+C什么的。再不你就再開一個外殼然后ps -ef再kill。再狠一些拆硬盤,撥電源我們這里有了一個新的函數(shù):execl()。其實他是一組函數(shù)中的一個。這組函數(shù)如下:int execl( path , arg0 , arg1 , . , argn ,
8、 (char *)0 );int execv( path , argv );int execle( path , arg0 , arg1 , . , argn , (char *)0 , envp );int execve( path , argv , envp );int execlp( file , arg0 , arg1 , . , argn , (char *)0 );int execvp( file , argv );其中的參數(shù)定義如下:char *path;char *file;char *arg0 , *arg1 , . , *argn;char *argv;char *envp
9、;返回值: 成功時:所執(zhí)行的命令將會覆蓋現(xiàn)有的進程,所以無返回值失敗時:-1用過TC的朋友應(yīng)該知道,TC的Process.h里有一個system()函數(shù)。這組函數(shù)其實和system()的功能差不多。比方說:execl( /bin/ls , /bin/ls , -al , /home , (char *)0 );或者char *argv;strcpy( argv0 , /bin/ls );strcpy( argv1 , -al );strcop( argv2 , /home );execv( /bin/ls , argv );都相當(dāng)于在命令行下敲入了/bin/ls -al /home并且回車。(
10、引號不是命令里的。是我解釋時加上去的。別看混了)。execle()和execve(),函數(shù)名最后一個字母都是e。就是說,這兩個函數(shù)在調(diào)用其它程序的同時,還可以把環(huán)境變量一起傳給被調(diào)程序execlp()和execvp(),函數(shù)名最后一個字母都是p,就是說,這兩個函數(shù)在使用的時候,就算你不指定命令文件所在的路徑,它也會根據(jù)環(huán)境變量PATH去挨個地方找。找著就執(zhí)行。找不著拉倒。比方說:setenv $path = ( /bin $path ) 這句話將環(huán)境變量PATH的第一個路徑設(shè)為/bin。這是在SHELL下執(zhí)行的。C里沒這東西吧。在程序中這樣用這個函數(shù)execlp( ls , ls , -al
11、, /home , (char *)0 );與上面的效果一樣。當(dāng)然。如果你PATH變量沒設(shè)好的話。它就不一定找到哪兒去了。還有一個函數(shù)是wait(),說明如下:#include pid_t wait(int *stat_loc);返回值就是一個PID了。忘了PID是什么意思的朋友光顧一下我上一篇貼子。它的參數(shù)有些意思。其實它與你的子進程用什么方式結(jié)束有關(guān)系。當(dāng)你的子進程以exit()方式結(jié)束的話,stat_loc所指向的地址的前8位將會是exit()的參數(shù)的后8位,而stat_loc所指向的地址的后8位是0。比方說:你的子進程是exit(1);那stat_loc所指向的地址的內(nèi)容應(yīng)該是0000
12、 0001 0000 0000。exit():#include void exit(int status);就算你在程序中沒寫exit()函數(shù),編譯器也是認為你是在最后加入了這個函數(shù)。下一篇貼子,咱們再把這個Shell完善一下本文所有程序均應(yīng)在UNIX系操作系統(tǒng)下編譯執(zhí)行。第三章:增強ssh的功能(使用環(huán)境變量)還記得上次做的那個ssh吧?這回咱們把它再改一改。大家知道。C語言的main函數(shù)是這樣的:int main( int argc , char *argv , char *envp );前兩個不用說了吧。其實知道前兩個的話應(yīng)該也知道第三個:取得系統(tǒng)環(huán)境變量。UNIX和DOS一樣。有著各種
13、各樣的環(huán)境變量(明確地說,應(yīng)該是比DOS用得更廣泛)。比方說常用的$PATH,$HOME,$USER等等。如果用的是csh,可以改 /.cshrc或者干脆直接在命令行下設(shè)就行了。這些是UNIX的東西,不屬于我們在C/C+討論的東西了。有興趣的朋友可以到UNIX版去看一看。下面是一個取得系統(tǒng)環(huán)境變量并輸出的小程序/* getenv.c 取得系統(tǒng)環(huán)境變量并輸出 */#includeint main ( int argc , char *argv , char *envp )int i;for( i=0 ; envpi!=NULL ; i+ )printf( %sn , envpi );return
14、 0;編譯執(zhí)行后應(yīng)該是這樣:%./getenvDISPLAY=:0.0HOME=/home/syuuiUSER=syuui以及你的系統(tǒng)中其它的環(huán)境變量。想一想它是怎么運行的:當(dāng)你在命令行下敲入getenv并回車,shell就fork出一個新的進程,然后讓這個進程去執(zhí)行g(shù)etenv,并把現(xiàn)在系統(tǒng)中的各個環(huán)境變量存入到envp里去。這個時候,原來shell的進程就是getenv進程的父進程。envp的參數(shù)是從父進程中取得的?,F(xiàn)在你知道上一節(jié)中為什么有那兩個帶p的函數(shù)了?上一回做的ssh這個外殼的命令是帶不了參數(shù)的。因為咱們的程序不知道要去讀參數(shù)。這回不妨做一個能讀參數(shù)的試試#include #de
15、fine SP 0#define NOSP 1void getarg( char *argv , char *p ); /取得各個參數(shù)int main()static char prompt64= ;char command256, *argv256, *p;int st;fprintf( stderr , %s , prompt );while( (p=gets(command)!=NULL )getarg( argv , p );if( fork()=0 )if( execv(argv0,argv)=(-1) )exit(1);elsewait( &st );fprintf( stderr
16、 , %s , prompt);return 0;void getarg( char *argv , char *p )int i , sp_flag ;sp_flag=SP; /SP代表空格,NOSP代表非空格的意思for( i=0 ; *p!=0 ; p+ )if( sp_flag=SP & *p!= )/如果現(xiàn)在狀態(tài)是讀過空格,但現(xiàn)在這個字母是非空格/那很顯然,讀到一個新的參數(shù)argvi=p;i+;sp_flag=NOSP;if( *p= )*p=0;sp_flag=SP;argvi=(char *)0;這篇文章東西說得比較少。給大家出個問題吧:看到了吧。C能做的事情很多。誰說C不支持多
17、進程?那是因為DOS。呵呵上回做的ssh,必須輸入絕對路徑才能執(zhí)行。現(xiàn)在要求,咱們做一個只輸入命令以及參數(shù),程序自動在$PATH里定義的各路徑查找這個命令。找到就執(zhí)行,找不到就報錯的外殼出來試試?有做出來的,請貼程序。2003-7-27 關(guān)于進程狀態(tài)的一些補足:眾所周知,UNIX是一個多用戶多任務(wù)的操作系統(tǒng)。所謂多任務(wù),就是指在同一個時間內(nèi),看上去有許多任務(wù)在同時執(zhí)行。這一點是與DOS不同的。所以Turbo C下找不到fork()函數(shù)。當(dāng)然。大家知道,實際上CPU同一個時間只能處理一件事。它是在輪流執(zhí)行這些進程,由于速度很快。所以看起來像是所有進程在一起跑。同樣,一個進程,它有使用CPU的時候
18、,也有等待使用CPU的時候。這就決定了進程的幾種狀態(tài)。進程大致可以分為“執(zhí)行中”,“準(zhǔn)備執(zhí)行”,“睡眠中”三種狀態(tài)。執(zhí)行中:進程在占用CPU。準(zhǔn)備執(zhí)行:想要使用CPU,但是CPU被別的進程占用中,所以等待CPU空閑。睡眠中:等待事件發(fā)生的進程。比方說,等待輸入輸出結(jié)束的進程。我們用fork()生成一個新的進程,或者用exec函數(shù)組覆蓋當(dāng)前進程后。當(dāng)這個子進程結(jié)束的時候要給父進程送去一個信號(signal,后述),然后轉(zhuǎn)為zombie狀態(tài)。zombie狀態(tài)是指一個進程已經(jīng)結(jié)束,所占內(nèi)存空間等等已經(jīng)返還給系統(tǒng),但是在系統(tǒng)的進程列表中仍然存在的這么一個狀態(tài)。當(dāng)父進程執(zhí)行wait()后,子進程才真正完
19、全結(jié)束。如果父進程先一步結(jié)束了,那么由init代替父進程。所以,wait()不只是等待子進程結(jié)束。它還有上面所說的這個任務(wù)。我們寫個程序來看一下:/* zombie */#includeint main()int st;if( fork()=0 )exit(1); /子進程生成后直接結(jié)束elsesleep( 300 ); /休眠300秒wait( &st );printf(Return code=%dn,i);return 0;編譯后執(zhí)行%./zombie &這個時候,程序在后臺運行%ps -ef | grep zombie看一下,是不是有一個進程處在zombie狀態(tài)?本文所有程序均應(yīng)在UNI
20、X系操作系統(tǒng)下編譯執(zhí)行。第四章:文件系統(tǒng)UNIX所管理的機器一般是大型機而不是PC。所管理的硬盤一般也非常大。所以一般分成幾個區(qū),每個區(qū)都有其單獨的文件系統(tǒng)。比方說你能大概能找到這樣的一些文件/dev/sd/c0t0d0s0/dev/sd/c0t0d0s1. .當(dāng)UNIX啟動的時候,分區(qū)被掛裝(mount)并統(tǒng)一成一個樹狀的文件系統(tǒng)分區(qū)的物理構(gòu)造咱們暫且放在一邊,先寫個程序,讀一下分區(qū)信息試試。/* ndf.c 計算參數(shù)所指定的分區(qū)的剩余空間比率 */#include #include #include int main(int argc , char *argv)struct statvfs
21、 buf1;sync();if( statvfs(argv1,buf)!=0 )fprintf(stderr , Cannot read super block !n);exit(1);fprintf(stderr , %4.1f % freen,(float)buf0.f_bfree / buf0.f_blocks*100 );return 0;編譯執(zhí)行:%./ndf /49.8 % free這里用了一個statvfs函數(shù)。其具體如下:#include#includeint statvfs( char *path , struct statvfs *buf );返回值: 成功時: 0失敗時:
22、 -1還有一個sync()函數(shù)。用來更新分區(qū)的super block;void sync();UNIX系統(tǒng)為了加快處理速度,將分區(qū)的super block信息讀到內(nèi)存中保存。sync()函數(shù)就是把在內(nèi)存中保存的super block信息再寫回到硬盤上去。UNIX系統(tǒng)使用好幾種文件系統(tǒng)。有S5,ufs,VxFS等等。雖然這些文件系統(tǒng)的構(gòu)造非常不同,但一通百通,咱們在這幾篇貼子里只討論一下比較容易理解,而且“經(jīng)典的”S5文件系統(tǒng)。(別的我也不會。呵呵)S5: 文件名最長14字節(jié),構(gòu)造簡單ufs: 文件名最長255字節(jié),BSD所用的文件系統(tǒng)。VxFS: Veritas Softwave公司開發(fā)的文件
23、系統(tǒng)。出現(xiàn)錯誤時可以快速恢復(fù)。由于這種文件系統(tǒng)保證文件在硬盤上連續(xù)存放,所以處理速度很快?,F(xiàn)在說一下S5分區(qū)的構(gòu)造一個分區(qū)包含如下四部分(按順序): boot block super block i node block data block boot block :這個部分在分區(qū)的最開始處,用來存放引導(dǎo)程序。就算是不能引導(dǎo)的分區(qū)一樣有boot block,這個時候這部分就沒有用了。不過一般這部分也不大。大多數(shù)只有512或者1024字節(jié)。super block :super block在boot block之后,用來存放這個分區(qū)全體的管理信息。上面那個ndf.c就是讀的這部分所存儲的信息。里邊
24、存放了i node block的大小,free block數(shù)組等等。根據(jù)這些信息可以得知data block的開始位置。i node block :i node是index node的縮寫。i node block就是存放i node的部分UNIX把一切都看成是個文件。包括目錄以及設(shè)備等等的所有的文件都有一個i node號,作為這個文件的管理信息。文件本身存在于數(shù)據(jù)區(qū),但是i node號存在i node block里。主要包含文件的模式,鏈接數(shù),文件所有者,文件大小,在硬盤上的位置,最后讀寫時間,最后更新時間等信息。為了加快存儲速度,系統(tǒng)會把一定數(shù)量的i node存至內(nèi)存。UNIX系統(tǒng)不一樣,
25、存多少也就不一樣。data block :這部分就是存放數(shù)據(jù)本身的了。這部分被分成一定大小的塊,如同DOS的扇區(qū)一樣。一般大小是1024字節(jié),分到4096的也有。解說到這里,我們再來寫個程序。打開一個目錄,然后把這個目錄下所有的文件的i node號及文件名輸出來。/* nls.c */#include #define DIRSIZ 14int main( int argc , char *argv )struct dirint i_no;char f_name;struct dir dir_data1;FILE *fp;fp=fopen(argv1,r);while( fscanf(fp,%i
26、%s,&(dir_data0.i_no),dir_data0.f_name)!=EOF )printf(%i %sn , dir_data0.i_no , dir_data0.f_name );fclose(fp);return 0;%./nls /. .2048 usr2049 home. .別忘了,在UNIX下,目錄也當(dāng)成文件。最近,為了使目錄的格式變得通用而不再依賴于操作系統(tǒng),程序中大多使用統(tǒng)一的格式。這種情況下,我們最好就不直接用fopen()打開目錄,而使用opendir(),readdir()等函數(shù)比較好。重寫一下上面的程序。/* nls2.c */#include #includ
27、e int main( int argc , char *argv )DIR *fp;struct dirent *p;fp=opendir(argv1);while( (p=readdir(fp)!=NULL )printf(%i %sn, p-d_ino , p-d_name );closedir(fp);return 0;執(zhí)行結(jié)果和上面一樣。函數(shù)說明如下:#include DIR *opendir( char *dirname ); 打開一個目錄,成功時返回DIR結(jié)構(gòu)體的地址,失敗返回NULLstruct dirent *readdir( DIR *dirp ); 取得打開目錄中下一個文
28、件的信息,成功時返回下一個文件信息的地址,失敗時,或者讀至末尾時返回NULLint closeidr( DIR *dirp ); 關(guān)閉目錄,成功時返回0,失敗時返回-1注意:readdir在成功地讀出一項之后,會自動指向下一項。假設(shè)你有如下程序:struct dirent *p;p=readdir(fp);p+; /千萬不要像這行這樣寫。你無法保證這目錄里的文件信息是連續(xù)存放的。你只要一遍一遍地用readir()這個函數(shù)就行了。它幫你全搞定本文所有程序均應(yīng)在UNIX系操作系統(tǒng)下編譯執(zhí)行。第五章:目錄及文件操作上一章我們說了一些UNIX的文件系統(tǒng)的物理構(gòu)造。下面我們來看看具體怎么對文件進行操作。
29、當(dāng)然這里所說的文件及目錄操作不是fopen()。呵呵。我們要做一些fopen辦不到的事。/* newer.c 比較參數(shù)所指定的兩個文件將其中新的文件的文件名輸出來 */#include #include #include int main( int argc , char *argvp )struct stat buf2 , *p ;if( argc!=3 )fprintf( stderr , Usage : %s file1 file2n , argv0 );exit(1);p=buf;if( stat(argv1,p)!=0 ) /取得第一個文件的信息fprintf( stderr , %
30、s not found !n , argv1 );exit(1);p+;if( stat(argv2,p)!=0 ) /取得第二個文件的信息fprintf( stderr , %s not found !n , argv2 );exit(1);if( buf0.st_mtime buf1.st_mtime ) /比較最終更新時間printf( %sn , argv1 );elseprintf( %sn , argv2 );return 0;執(zhí)行結(jié)果:%newer afile bfilebfile使用stat()函數(shù),可以得到文件的信息。這些信息是在i node中保存的這個文件信息的一部分。得到
31、的信息將會保存在stat.h中定義的stat型的結(jié)構(gòu)體中。stat()函數(shù)解釋如下:#include #include int stat( char *path , struct stat *buf );返回值: 成功時:0失敗時:-1我們再來寫一個玩玩 #include #include #include #define MASK 0555 /這個數(shù)字的意思等一下解釋,他代表“可讀”和“可執(zhí)行”int main( int argc , char *argv )struct stat buf1;mode_t mode;if( argc!=2 )fprintf( stderr , Usage :
32、 %s filen , argv0 );exit(1);if( stat(argv1,buf)!=0 )fprintf( stderr , Cannot read i-noden );exit(1);mode = ( buf0.st_mode & MASK ); /計算文件新的權(quán)限標(biāo)志if ( chmod(argv1,mode)!=0 ) /改變文件的權(quán)限標(biāo)志fprintf( stderr , Cannot change moden );exit(1);return 0;現(xiàn)在來解釋一下0555這個數(shù)字的意思。眾所周知,UNIX是一個多用戶多任務(wù)的操作系統(tǒng)。每個用戶有自己的權(quán)限,這個權(quán)限限制了用
33、戶可以做哪些事,不可以做哪些事。對于文件來說,用戶可以分成四類:root(根用戶,超級用戶)這個用戶是系統(tǒng)的管理吶,權(quán)限最大,可以隨意讀寫任何文件。owner(文件擁有者)實際擁有文件的用戶。文件屬主。group(組成員)用戶所在的用戶組的成員other以上三類之外的其它用戶UNIX中,每個文件信息中包括一組9位的權(quán)限標(biāo)志。分別給文件屬主,用戶組和其他用戶指定對該文件的讀、寫和執(zhí)行權(quán)。請看下面的例子:%ls -l /bin/ls-rwxr-xr-x 1 root bin 27281 Aug 15 2002 /bin/ls*重要是看-rwxr-xr-x,第一個 - 表示這是一個普通文件,這個位置
34、也可以出現(xiàn)些別的字符,比方說目錄的話這里會是 d 。而 l 表示一個鏈接。余下的9位可以分成三段,每段三位。本例中從左至右rwx 表示文件的屬主擁有文件的讀,寫,執(zhí)行權(quán)r-x 表示同組的用戶擁有文件的讀,執(zhí)行權(quán)(注意 ,“寫”權(quán)限的位置是一個 - )r-x 表示其它的用戶擁有文件的讀,執(zhí)行權(quán)文件的訪問權(quán)限還可以用三位8進制來表示。如上例rwx r-x r-x 可以換成111 101 101 (有該權(quán)限,則該位為1,否則為0)換成8進制, 二進制的111是八進制的7 , 二進制的101是八進制的5?,F(xiàn)在看看0555是什么意思?就是說,可以讀,可以寫的意思。把0555和原來文件的權(quán)限標(biāo)志做與運算,
35、得到的新的權(quán)限標(biāo)志就是把原來的文件權(quán)限標(biāo)志中所有的寫權(quán)限全取消了。其余權(quán)限變。然后在程序中用chmod()把這個新的權(quán)限標(biāo)志賦給文件即可。chomd()函數(shù)用法如下:#include #include int chmod( char *path , mode_t mode );返回值: 成功時:0失敗時:-1關(guān)于目錄,還有另一個比較有用的函數(shù),即chdir()。用這個函數(shù)可以在程序中轉(zhuǎn)換當(dāng)前目錄。#include #include int chdir( char *path );返回值: 成功時:0失敗時:-1以上兩章,簡單地敘述了一下UNIX的文件系統(tǒng)以及在UNIX C中對文件的操作方法。并
36、列舉了常用的一些函數(shù)。下一章,我們將簡單地敘述一下UNIX C的輸入輸出,以及用管道(pipe)實現(xiàn)兩個進程互換數(shù)據(jù)。本文所有程序均應(yīng)在UNIX系操作系統(tǒng)下編譯執(zhí)行。第六章:標(biāo)準(zhǔn)輸入輸出以及管道操作標(biāo)準(zhǔn)輸入輸出大概所有的操作系統(tǒng)都差不多吧。從鍵盤輸入。從屏幕輸出。除非你用的還是打紙帶的老家伙。呵呵。主要說一下管道操作。注意:此處所說的管道操作不是% cat -n test.c | more 這是在提示符狀態(tài)下使用管道,把第一個程序(cat)的輸出作為輸入傳給第二個程序(more)。我們現(xiàn)在要在程序中使用的管道原理與此相同。將某一個程序的輸出變?yōu)榱硪粋€程序的輸入。做一個石頭剪子布的程序。其中包括
37、一個父程序和一個子程序。注意是兩個程序,不是兩個函數(shù)。也不是兩個進程。不過因為父程序運行的時候要通過exec()函數(shù)來執(zhí)行子程序。所以我們也可以把它看成是兩個進程。父進程取得用戶的輸入(石頭S,剪子C,布P中的某一個,P=0,S=1,C=2)并通過管道傳給子進程子進程取得父進程傳來的數(shù)字,加上自己的PID后做為種子數(shù),生成一個隨機數(shù)然后被3除,得出來一個余數(shù)是0、1或者2。再通過管道傳回給父進程。父進程根據(jù)兩個數(shù)字(用戶輸入的,以及子進程傳回來的)判定勝負,輸出/* parent. */#include #include int main()int i , j ,st , fd2 ;pid_t
38、 pid ;static int result33=1,0,2,2,1,0,0,1,2;char argv13 , argv23 ,ch ;ch=getchar();switch(ch)case P: i=0;break;case S: i=1;break;case C: i=2;break;default:fprintf( stderr , Enter P , S or C , Please!n );exit(1);if( pipe(fd)!=0 ) /建立管道fprintf( stderr , PIPE Error !n );exit(1);sprintf( argv1 , %d , fd
39、0 );sprintf( argv1 , %d , fd1 );switch( pid=fork() ) / fork出一個新的進程,執(zhí)行子程序case 0:if( execl(child,child,argv1,argv2,(char *)0) = (-1) exit(1);/執(zhí)行了子程序break;case -1:fprintf( stderr , fork Error !n );exit(1)write( fd1, &i , sizeof(i) ); /向管道寫數(shù)據(jù)wait( &st ); /等待子程序結(jié)束read( fd0 , &j , sizeof(j) ); /從管道讀數(shù)據(jù)swit
40、ch(resultij)case 0:printf( You wonn );break;case 1:printf( Samen );break;case 2:printf( You lostn );close(fd0);close(fd1);return 0;/* child.c */#include int main(int argc , char *argv)int i,j,read_fd,write_fd;read_fd=atoi( argv1 ); /設(shè)定輸入用管道write_fd=atoi( argv2 ); /設(shè)定輸出用管道read( read_fd , &i , sizeof(
41、i) ); /從管道中取得數(shù)據(jù)srand( i+getpid() ); /設(shè)定隨機數(shù)的種子數(shù)j=rand()%3; /生成隨機數(shù)write( write_fd , &j , sizeof(j) ); /寫向管道close( read_fd );close( write_fd );return 0;編譯執(zhí)行父程序即可。這種管道是用來在父子進程間傳遞數(shù)據(jù)的。如同大家在程序中所見:父進程開辟管道,然后生成子進程執(zhí)行子程序,并將管道參數(shù)作為main()函數(shù)的參數(shù)傳給子程序。通過一個相同的管道實現(xiàn)讀寫。開辟管道時,我們用到了這個函數(shù):int pipe( int fd2 ); 開辟一個管道參數(shù)fd2是一個
42、有兩個元素的數(shù)組??梢钥闯墒莾蓚€管道的記述子。fd0用來讀,fd1用來寫。返回值: 成功時:0失敗時:-1讀取/寫入管道時,我們用到了下面函數(shù)讀取管道中的數(shù)據(jù)int read( int fd , char *buf , unsigned int nbyte );向管道中寫入數(shù)據(jù)int write( int fd , char *buf , unsigned int nbyte );其中,fd是管道記述子,也就是我們前面說的fd0或者fd1,buf裝數(shù)據(jù),nbyte指定讀/寫數(shù)據(jù)的數(shù)量,單位是字節(jié)。成功時返回0,失敗時返回-1。由于準(zhǔn)備考研。這篇文章耽誤了一些時日。最近還有些事,也許下一篇也得幾
43、天后才能再貼。另外,在此向諸位致歉。我的程序是在學(xué)校的UNIX下寫的,一般是用軟盤帶回來,寫上一篇貼子程序的時候沒有帶軟盤,只好打印出來回來再敲。在輸入的時候有一個錯誤(現(xiàn)已改正)int main( int argc , char *argvp);應(yīng)為int main( int argc , char *argv);下一章準(zhǔn)備說說UNIX的進程(Process)和信號(signal)。另外,感謝版主將我前幾篇貼子選進了精華區(qū)。愚作不堪,如有錯誤及不到之處請諸位高人指正為盼。對本貼內(nèi)容如有不明,請給我留言。我會盡快回答(如果我明白的話)。謝謝遠方的潔白的哈達,霧中雪,初學(xué)無罪,hellosam,
44、xiaoyu等朋友。有你們的支持,我才有信心繼續(xù)寫下去。愿拙文能對諸位學(xué)習(xí)C語言有所幫助。下章見。本文所有程序均應(yīng)在UNIX系操作系統(tǒng)下編譯執(zhí)行。第七章:UNIX進程(Process)及信號(signal)在進程執(zhí)行過程中,如果出現(xiàn)什么事件(event),系統(tǒng)將會給進程一個信號。進程可以在得到這個信號后做些適當(dāng)?shù)奶幚?。還是與以前一樣,咱們先來個小程序吧。/* slot.c */#include #include int x3;long kin;int kekka();int main( int argc , char *argv )srand( getpid() ); /* 設(shè)定隨機數(shù)的種子數(shù)
45、 */signal( SIGKILL , kekka ); /* 當(dāng)Ctrl+C按下時,執(zhí)行kekka函數(shù) */kin = atoi( argv1 ); /* 取得賭注數(shù)目 */printf(press Ctrl+C to stop maching !n);while(1)x0=rand()%10;x1=rand()%10;x2=rand()%10;printf(%d %d %dn,x0,x1,x2);fflush( stdout );return 0;int kekka() if( x0=x1 & x1=x2 ) printf(Great , you won %d n , kin*3000)
46、;elseprintf(You lost %dn,kin);exit(0); /* 游戲結(jié)束。退出程序 */執(zhí)行方法:%./slot 100執(zhí)行后。畫面上會出現(xiàn)一排排的數(shù)字。當(dāng)你按下Ctrl+C的時候,程序得到信號,跳轉(zhuǎn)至kekka()函數(shù)入,判斷隨機數(shù)。然后退出程序。這里有這樣一個新函數(shù)。是我們在UNIX程序設(shè)計中時常用得到的。#include int ( *signal( int sig , void (*func() )();返回值: 成功時:進程中斷地址錯誤時:SIG_ERR這個函數(shù)挺不好懂呵。解釋解釋。它的意思是,當(dāng)收到SIG這個信號時,跳轉(zhuǎn)至func()這個函數(shù)處繼續(xù)執(zhí)行。int
47、sig這個參數(shù)其實好辦。下面我們會給出一個表。將其所有的參數(shù)一并列出。這是在頭文件中#define的,代表各種不同的信號。void ( * func() )這個參數(shù)是一個函數(shù)指針。意思是在SIG信號被傳給進程后,所要執(zhí)行的部分。此外,func()這個參數(shù)還可以為如下值:SIG_DEL 系統(tǒng)的默認動作SIG_IGN 忽略這個信號。signal作用只有一次,當(dāng)一個信號發(fā)生,觸發(fā)signal動作的之后,signal就不起作用了。比方說,在上例中,如果你把所有的exit(0)全去掉(不退出程序),程序會進入無限循環(huán)中。你按一次Ctrl+C,signal執(zhí)行一次,顯示出結(jié)果。然后繼續(xù)循環(huán),生成隨機數(shù),輸
48、出。你再按Ctrl+C,signal就不好使了。如果需要重復(fù)使用signal()函數(shù),可以考慮在signal調(diào)用的動作函數(shù)中再加一個signal,比方說在上例的程序中再加一個 signal( SIGKILL , kekka );加了signal這個函數(shù)后,整個程序如果沒收到信號,則正常執(zhí)行。否則跳轉(zhuǎn)至signal中指定的func()函數(shù)處繼續(xù)。當(dāng)然,我們不可能,也沒有必要去為每一個信號指定一個動作。當(dāng)未指定動作的信號發(fā)生的時候,系統(tǒng)會執(zhí)行默認的動作。比方說我們知道:當(dāng)Ctrl+C按下的時候,正常默認的動作是結(jié)束程序。但是,Ctrl+C按下時,發(fā)生的信號是SIGKILL,如果你為SIGKILL這
49、個信號指定了一個動作的話,系統(tǒng)將去執(zhí)行你指定的這個動作,而不管原來默認的了。打個比方讓大家更容易懂一些:比方說:你在睡午覺。突然來了一個美女(帥哥)(Ctrl+C)讓你陪她/他去逛街購物共進晚餐(此處刪去若干字),你正常的默認的動作是馬上起來陪她出去玩(程序中止)。但是你媽說不許去,你媽說你得在家擦窗戶,你只好留在家擦窗戶(signal()指定的動作)。擦完窗戶之后你可以選擇陪美女去逛街(默認動作,Ctrl+C的埸合是退出程序,即上例程序中的exit(0)),可以選擇繼續(xù)睡覺(回到原來中斷的地方繼續(xù)執(zhí)行,上例程序中如果沒有exit(0),便會回到中斷處繼續(xù)執(zhí)行)。(大哥。打個比方嘛。干嘛拿臭雞
50、蛋砸我)signal種類非常多,在此不一一列出。使用這個函數(shù),你可以防止用戶按下Ctrl+C結(jié)束程序。還可以做很多其它的事只有你想不到的,沒有C做不到的。注意:根據(jù)UNIX系統(tǒng)的不同,signal的定義是不一樣的。比方說,有的老式UNIX工作站上SIGINT是按下del鍵后發(fā)生的信號,而有些機型上剛是按下Ctrl+Z發(fā)生的。在使用時要注意。再一次感謝SOHU C/C+論壇的朋友們的支持。我考上研究生了。下一次,準(zhǔn)備說說UNIX下C程序中,如何向別的進程發(fā)送信號。本文所有程序均應(yīng)在UNIX系操作系統(tǒng)下編譯執(zhí)行。第八章:向其它進程傳遞信號上一章,我們簡單地說了一下信號。信號不僅僅可以在本進程內(nèi)使用
51、,還可以向其它的進程傳遞。確切地說,一般情況下,一個進程收到的信號絕大部分是從系統(tǒng)的INIT傳來的。而INIT也是一個進程。用過UNIX或者LINUX的朋友大概都知道,UNIX系的操作系統(tǒng)里,有一個kill命令。如果你的一個進程無法中止,可以使用kill命令強行干掉它。%kill mypro我們自己也可以做個簡單的kill命令。/* nkill.c */#include #include #include int main( int argc , char *argv )pid_t pid;if( argc != 2 ) / 檢查命令行參數(shù)個數(shù)fprintf( stderr , Usage :
52、 %s PID n , argv0 );exit(1);pid = atol( argv1 );if( kill( pid , SIGKILL )!=0 ) / 向pid這個進程傳送一個SIGKILL信號fprintf( stderr , kill failedn );return 0;執(zhí)行例:%sleep 300 & (后臺睡眠300秒)1 520%nkill 5201 + Killed sleep 300你用自己寫的程序殺死了一個sleep進程。沒事。殺了就殺了吧。留著也是垃圾說明一下,眾所周知,UNIX是非常注意用戶的權(quán)限的。所以,如果你向你自己生成的進程發(fā)送SIGKILL的話,這個進程
53、會中止。如果你是向別的(你沒有寫權(quán)限的)進程發(fā)送SIGKILL的話,除非那個進程允許你動它,否則你發(fā)了也是白發(fā)。打個不恰當(dāng)?shù)谋容^下流一些的比方:如果你要求親一下你自己老婆的話(你有“親”的權(quán)限),你會如愿以償。但是如果你想親一下別人的老婆的話(你沒有“親”的權(quán)限),除非他及她同意,否則呵呵。你死定了。所以,執(zhí)行上面的程序的時候,你必須保證你有權(quán)限關(guān)掉那個進程??刹皇钦f你ps -ef然后隨便挑一個進程就能關(guān)的。要不那黑客也太好當(dāng)了。幾乎是咱們的老規(guī)矩了:先寫個程序,然后解釋這個程序,說說其中新出現(xiàn)的函數(shù)。這回還照舊吧。大家看到了。這里新出來一個kill()函數(shù)。解釋如下:#include #include int kill( pid_t pid , int sig );返回值: 成功時:0失敗時:-1這個函數(shù)是向進程ID(PID)為pid的進程傳送一個sig信號。這個函數(shù)有什么用呢?用處可大了。在上一章中,我們用到了SIGKILL信號。這一節(jié)我們用的還是這個信號。實際上,信號(signa
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 河南省周口市川匯區(qū)2024-2025學(xué)年八年級上學(xué)期期中質(zhì)量監(jiān)測語文試卷(無答案)
- 社經(jīng)大勢解密-揭示市場前景與決策因素
- 2014-2020年全球格拉辛紙行業(yè)市場深度調(diào)查與投資規(guī)劃分析研究報告
- 2011-2016年P(guān)ET注坯模具行業(yè)動態(tài)預(yù)測報告
- 2024至2030年中國變壓器磁芯數(shù)據(jù)監(jiān)測研究報告
- 2024至2030年中國仙人糧晶數(shù)據(jù)監(jiān)測研究報告
- 2024年中國立軸圓臺平面磨床市場調(diào)查研究報告
- 2024年中國電源保護分配器市場調(diào)查研究報告
- 2024年中國便攜式示波器市場調(diào)查研究報告
- 2024年中國交接器市場調(diào)查研究報告
- 重型運輸培訓(xùn)課件
- 乳腺結(jié)節(jié)健康科普知識講座
- 兒童成長發(fā)育的親子關(guān)系
- 新《行政處罰法》修訂要點解讀
- 數(shù)學(xué)有理函數(shù)不等式課件
- 2024年中鐵四局集團有限公司招聘筆試參考題庫含答案解析
- 噸桶使用管理制度
- 《地球上的海洋》課件
- 城市軌道交通概論綜合測試題(完整答案版)10
- 中考化學(xué) 復(fù)習(xí)專題經(jīng)驗介紹課件 人教新課標(biāo)版
- 《體育心理學(xué)》課件
評論
0/150
提交評論