实验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;

}

测试程序

编译程序:

rongxiangliu@Ubuntu:~$ gcc getstatus.c -o getstatus

 

(1)首先测试WIFEXITED正常退出情况,执行:

rongxiangliu@Ubuntu:~$ ./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)便于测试):

rongxiangliu@Ubuntu:~$ ./getstatus

child --- my parent is 641812

此时另开一终端,查看进程,kill命令终止子进程:

rongxiangliu@Ubuntu:~$ 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

rongxiangliu@Ubuntu:~$ kill 6438

此时子进程异常终止,getstatus  程序输出信息:

rongxiangliu@Ubuntu:~$ ./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:

rongxiangliu@Ubuntu:~$ 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);

}     

猜你喜欢

转载自blog.csdn.net/CSDNwbdream/article/details/83893944