1. 程式人生 > >實驗4 Linux程序控制實驗指導書

實驗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()是一個阻塞函式,如果沒有可以回收的子程序,則為阻塞狀態;如果無子程序,則返回

-1;如果回收成功,則返回子程序的pid返回值。wait() 只有一個引數,可以為NULL,也可以為int* status。所需要的標頭檔案為<sys/type.h><sys/wait.h>

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));  

    }

 

3WIFSTOPPED(status)WSTOPSIG(status)

WIFSTOPPED(status)為非0 表明程序處於暫停狀態。若WIFSTOPPED(status)為真,此時可通過WSTOPSIG(status)獲取使得程序暫停的訊號編號 。

4WIFCONTINUED(status)

WIFCONTINUED(status)為非0表明一個暫停的子程序被訊號SIGCONT喚醒。

2. WIFEXITEDWIFSIGNALED用法完整程式:

#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);

}