實驗4 Linux程序控制實驗指導書
實驗4 Linux程序控制實驗指導書
一、Ubuntu18下安裝fcitx及中文輸入法
1、解除安裝IBUS
sudo apt-get remove ibus
sudo apt-get purge ibus
2、開啟 ubuntu 軟體中心,搜尋 fcitx,把3個帶企鵝圖示的軟體都安裝上;
3、安裝五筆拼音碼錶,sudo apt-get install fcitx-table-wbpy,
安裝雲拼音:sudo apt-get install fcitx-module-cloudpinyin,
安裝fcitx自帶的全部拼音,這裡根據你的需要進行安裝。
4、sudo apt remove fcitx-ui-classic,防止出現兩個輸入法圖示;
5、在 /usr/share/applications 路徑中找到並執行 Startup Applications,把fcitx設為自啟動,防止Ubuntu登出後輸入法消失;
6、選擇fcitx為系統輸入法
7、最後一步,重啟Ubuntu;
8、若fcitx輸入配置列表裡不顯示已經安裝的輸入法,用下面命令修正:
sudo apt-get install fcitx-rime
9、gedit中文亂碼
gsettings set org.gnome.gedit.preferences.encodings Candidate Encodings "['GB18030', 'UTF-8', 'CURRENT', 'ISO-8859-15', 'UTF-16']"
10、若終端printf輸出中文亂碼,那麼在終端中進行如下設定:Terminal->Set Character Encoding->Chinese Simplified-GB18030
二、深入理解wait/waitpid函式及其引數
wait()是一個阻塞函式,如果沒有可以回收的子程序,則為阻塞狀態;如果無子程序,則返回
而waitpid()是對wait()函式的優化,在父程序使用wait()函式時,因為這個函式是處於阻塞狀態的,使父程序不能處理其他事情,這樣便浪費了父程序的資源,所以引出了waitpid()。
waitpid()非阻塞,
返回值 -1:失敗或者沒有回收子程序返回-1;
>0: 返回回收的子程序ID
0:代表子程序未結束,非阻塞輪詢返回。
waitpid()函式有三個引數:
(一)引數pid_t pid
pid_t 實際上就是int型別。
引數pid為欲等待的子程序識別碼,其具體含義如下:
pid<-1:等待程序組號為pid絕對值的任何子程序;
pid=-1:等待任何子程序,此時的waitpid()函式就退化成了普通的wait()函式。
pid=0:等待程序組號與目前程序相同的任何子程序,也就是說任何和呼叫waitpid()函式的程序在同一個程序組的程序。
pid>0:等待程序號為pid的子程序。
(二)引數 status
引數status將儲存子程序的狀態資訊,有了這個資訊父程序就可以瞭解子程序為什麼會退出,是正常退出還是出了什麼錯誤。當然,如果不關心子程序為什麼退出的話,也可以設為0。
引數status中,某些位表示退出狀態(正常返回),其它位則指示訊號編號(異常返回),有一位指示是否產生了一個core檔案等等。
1.常用的四組巨集函式
有四組互斥的巨集可用來取得程序終止的原因,即巨集幫助我們分析status各個
位上的值從而得出程序終止的原因。
(1) WIFEXITED(status)和 WEXITSTATUS(status)
WIFEXITED(status) 若此值為非0 表明程序正常結束。若WIFEXITED(status)為真,此時可通過WEXITSTATUS(status)獲取程序退出狀態(exit時引數) 。
示例:
if(WIFEXITED(status)){
printf("退出值為 %d\n", WEXITSTATUS(status));
}
(2) WIFSIGNALED(status) 和WTERMSIG(status)
WIFSIGNALED(status)為非0 表明程序異常終止。若WIFSIGNALED(status)為真,此時可通過WTERMSIG(status)獲取使得程序退出的訊號編號。
用法示例:
if(WIFSIGNALED(status)){
printf("使得程序終止的訊號編號: %d\n",WTERMSIG(status));
}
(3)WIFSTOPPED(status)和WSTOPSIG(status)
WIFSTOPPED(status)為非0 表明程序處於暫停狀態。若WIFSTOPPED(status)為真,此時可通過WSTOPSIG(status)獲取使得程序暫停的訊號編號 。
(4)WIFCONTINUED(status)
WIFCONTINUED(status)為非0表明一個暫停的子程序被訊號SIGCONT喚醒。
2. WIFEXITED和WIFSIGNALED用法完整程式:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid, wpid;
int status;
pid = fork();
if(pid == 0){ //子程序
printf("child --- my parent is %d\n", getppid());
sleep(30); //子程序睡眠30秒
printf("child is die\n");
}else if(pid>0){ //父程序
wpid = wait(&status); //等待回收子程序
if(wpid == -1){ //如果呼叫程序沒有子程序,呼叫就會失敗,此時wait返回-1
perror("wait error:");
exit(1);
} //正常退出判斷
if(WIFEXITED(status)){
printf("child exit with %d\n", WEXITSTATUS(status));
}
//因為某種訊號中斷獲取狀態
if(WIFSIGNALED(status)){
printf("child killed by %d\n", WTERMSIG(status));
}
while(1)
{
printf("parent pid = %d, sonpid = %d\n", getpid(), pid);
sleep(1);
}
} else {
perror("for error");
exit(1);
}
return 0;
}
測試程式
編譯程式:
[email protected]:~$ gcc getstatus.c -o getstatus
(1)首先測試WIFEXITED正常退出情況,執行:
[email protected]:~$ ./getstatus
child --- my parent is 6408
child is die
child exit with 0
parent pid = 6408, sonpid = 6409
parent pid = 6408, sonpid = 6409
parent pid = 6408, sonpid = 6409
parent pid = 6408, sonpid = 6409
....
(2)測試WIFSIGNALED訊號終止,執行(sleep(300)便於測試):
[email protected]:~$ ./getstatus
child --- my parent is 641812
此時另開一終端,檢視程序,kill命令終止子程序:
[email protected]:~$ ps aux | grep getstatus
rongxia+ 6437 0.0 0.0 4224 784 pts/18 S+ 21:58 0:00 ./getstatus
rongxia+ 6438 0.0 0.0 4356 84 pts/18 S+ 21:58 0:00 ./getstatus
rongxia+ 6442 0.0 0.0 21292 976 pts/4 S+ 21:58 0:00 grep --color=auto getstatus
[email protected]:~$ kill 6438
此時子程序異常終止,getstatus 程式輸出資訊:
[email protected]:~$ ./getstatus
child --- my parent is 6437
child killed by 15
parent pid = 6437, sonpid = 6438
parent pid = 6437, sonpid = 6438
parent pid = 6437, sonpid = 6438
parent pid = 6437, sonpid = 6438
...
如上所知,使得程序終止的訊號編號為15,通過 kill –l可知15號訊號為SIGTERM:
[email protected]:~$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
…
3.引數options
引數options提供了一些另外的選項來控制waitpid()函式的行為。如果不想使用這些選項,則可以把這個引數設為0。主要使用的有以下兩個選項:
WNOHANG:如果pid指定的子程序沒有結束,則waitpid()函式立即返回0,而不是阻塞在這個函式上等待;如果結束了,則返回該子程序的程序號。
WUNTRACED:如果子程序進入暫停狀態,則馬上返回。
這些引數可以用“|”運算子連線起來使用。
如果waitpid()函式執行成功,則返回子程序的程序號;如果有錯誤發生,則返回-1,並且將失敗的原因存放在errno變數中。
失敗的原因主要有:沒有子程序(errno設定為ECHILD),呼叫被某個訊號中斷(errno設定為EINTR)或選項引數無效(errno設定為EINVAL)
如果像這樣呼叫waitpid函式:waitpid(-1, status, 0),這此時waitpid()函式就完全退化成了wait()函式。
三、附教材程式
#include <sys/wait.h>
#include <sys/types.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>//包含巨集定義EXIT_SUCCESS等
#include <unistd.h>//包含sleep()
int main(void)
{
pid_t childpid;//pid_t實際上就是int型別
int status;
int retval;
childpid=fork();
if(-1==childpid)
{
perror("fork()");//用來將上一個函式發生錯誤的原因輸出到標準裝置(stderr)。
//引數 s 所指的字串會先打印出,後面再加上錯誤原因字串
exit(EXIT_FAILURE);//在<stdlib.h>中定義的巨集 EXIT_SUCCESS為0,EXIT_FAILURE為1
}
else
if(0==childpid)
{
puts("In child process");
printf("子程序號=%d,子程序睡眠100秒\n",(int)getpid());//getpid()返回當前程序的 標識
sleep(100);
exit(EXIT_SUCCESS);
}
else
{
printf("父程序號=%d,父程序等待子程序結束,若未結束則立即返回\n",
(int)getpid());
if(0==(waitpid(childpid,&status,WNOHANG)))//立即返回 W NO HANG 不阻塞模式
{
printf("殺死子程序前當前的活躍程序\n");
retval=kill(childpid,SIGKILL);
printf("父程序殺死子程序 \n");
if(retval)
{
puts("kill failed.");
perror("kill");
waitpid(childpid,&status,0);
}
else
{
printf("%d killed\n",childpid);
printf("殺死子程序後當前的活躍程序\n");
}
}
}
exit(EXIT_SUCCESS);
}