实验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。所需要的头文件为
而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
#include
#include
#include
#include
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
#include
#include
#include
#include
#include
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);//在
}
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);
}