第十章讲的是调试,这个调试没什么好说的,全靠经验和熟练度,刚用GDB那会,简直要我的命,不过现在用着用着也熟悉了。就没什么太大的感觉了。首先恭喜下锋哥拿到offer,加油啊!!顺便吐槽一下,操作系统的课真心太无聊了,每节课都是照着PPT讲,概念解释也不清楚,模棱两可就跳过去了。当然了,老师还是不错的。作为学生,肯定不能批评老师。老师之所以能当老师,总有自己的有点。不过这样的课,缺乏激情,毕竟自己看书也能得到同样的理解深度。那为何要上课呢?真心无语。
今天学习了Linux程序设计第十一章:进程和信号
1.进程的结构和描述什么的就不说了.
其中进程还有一些STAT代码,比如说S表示休眠,R表示运行之类的...
2.进程的调度,Linux进程中有一个nice值,初始为0.如果一直执行,nice值就会一直变差,如果等到某个输入,就会获得奖励.可以用nice值来决定优先级.我们可以用nice命令设置进程的nice值,也可以使用renice命令来调整他的值.比如说要对进程ID为1136的进程重新调整nice值,可以 这么运行 renice 10 1136,这将把1136的nice值增加10.
3.启动新进程.
我们可以在一个程序的内部启动另一个程序,这个可以简单的通过库函数system 来完成.
#include<stdlib.h>
int system(const char *string);
运行字符串的命令.命令的执行情况如同在shell中执行以下命令:
sh -c 命令 。system函数一般用处不大,因为它需要启动新的shell来运行程序,这个对环境依赖大,而且也不理想。一般我们用以下函数来启动进程。
#include<unistd.h>
char **environ;
int execl(const char *path,const char *arg0,...,(char *)0);
int execlp(const char *file,const char *arg0,...,(char *)0);
int execle(const char *path,const char *arg0,...,(char *)0,char *const envp[]);
int execv(const char *path,char *const argv[]);
int execvp(const char *file,char *const argv[]);
int execve(const char *path,char *const argv[],char *const envp[]);
这些函数可以分为两类,其中execl,execlp,execle支持可变参数。参数用一个空指针结束。execv和execvp第二个参数是一个字符串数组。不管哪种情况,新程序在启动时会把在argv数组中给定的参数传递给main函数。
这些函数通常是用execve实现的。虽然并不是必须要这么做。
以字符P结尾的函数通过搜索PATH环境变量来查找新程序中的可执行文件的路径。如果可执行文件不再PATH定义的路径中,我们就需要把包括目录在内的使用绝对路径的文件名作为参数传递给函数。
全局变量environ可用来把一个值传递到新的程序环境中。此外,函数execle和execve可通过参数envp传递字符串数组作为新程序的环境变量。
如果想通过exec函数来启动ps程序,我们可以这么写。
#include<unistd.h>
char *const ps_argv[] = {"ps“,”ax“,0};
char *const ps_envp[] = {"PATH=/bin:/usr/bin","TERM=console“,0};
execl("/bin/ps","ps","ax",0);
execlp("ps","ps","ax",0);
execle("/bin/ps","ps","ax",0,ps_envp);
execv("/bin/ps",ps_argv);
execvp("ps",ps_argv);
execve("/bin/ps",ps_argv,ps_envp);
这里需要注意的是,当我们用exec函数执行时,一般不会有返回,除非发生了错误。他的进程PID,PPID,和nice值都跟原先的一样。但是exec函数执行完毕之后,不会在返回原来调用他的函数了。这点跟fork不一样。所以exec是 替换进程映像,而fork是复制进程映像。
至于fork这个就不需要多说了。子进程返回0,父进程返回子进程ID。
等待一个进程,可以在父进程中调用wait来等待子进程的结束。
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int *stat_loc);
如果stat_loc不是空指针,状态信息会写入它所指的位置。我们可以用sys/wait.h文件中定义的宏来解释状态信息。 这个具体我就不打了,用的的时候百度。
当然,还有一个waitpid系统调用来等待子进程的结束。
#include<sys/types.h>
#include<sys/wait.h》
pid_t waitpid(pid_t pid,int *stat_loc,int options);
4.僵尸进程。
这尼吗听起来这么那么吓人。草。其实意思就是说,我们一个进程已经不再运行了,但是却要等待另外一个进程的结束,这个进程才能结束。而假设说那个进程突然间异常了,那这个不在工作的进程也就结束不了,只有等到init来清理他们。这就是僵尸进程。
5.假设说,我们有一个程序,它将文本中所有小写完全转换为大写。那么我们在另一个程序中要怎么调用这个程序呢?这里给出一个简单示例:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
char *filename;
if(argc != 2)
{
exit(1);
}
filename = argv[1];
if(!freopen(filename,"r",stdin))
{
exit(2);
}
execl("./upper","upper",0);
//注意,如果exec没有发生错误,下面这句将不会执行。
perror("could not exec ./upper");
exit(3);
}
6.信号。
信号的名称在头文件signal.h中定义。
程序可以用signal库函数来处理信号。定义如下:
#include<signal.h>
void (*signal(int sig,void (*func)(int)))(int);
这个狗血的函数说明。signal是带有sig和func两个参数的函数。准备捕获或者忽略的信号由参数sig给出,接收到指定的信号后将要调用的函数有参数func给出。其中signal函数本身也返回一个同类型的函数。即先前用来处理这个信号的函数,或者也可以用SIG_IGN(忽略信号)和SIG_DFL(恢复默认行为),两个之一来替代.
当然了,如今的程序已经不再推荐用signal了建议不要使用.而使用更可靠的sigaction来实现.
7.发送信号.
#include<sys/types.h>
#include<signal.h>
int kill(pid_t pid,int sig);这个函数把参数sig给定的信号发送给有参数pid给出的进程号所制定的进程.当然,需要一定的权限.否则将失败返回-1.
8.sigaction一个健壮的信号接口
#include<signal.h>
int sigaction(int sig,const struct sigaction *act,strucct sigaction *oact);
这个好像有点小复杂...到时候在研究研究.
十一章结束,有点小失落,如果给我重新来过大学,我一定不会像现在这样子.可是世事难料,奈何?就这样吧.
爱生活,爱编程.
今天学习了Linux程序设计第十一章:进程和信号
1.进程的结构和描述什么的就不说了.
其中进程还有一些STAT代码,比如说S表示休眠,R表示运行之类的...
2.进程的调度,Linux进程中有一个nice值,初始为0.如果一直执行,nice值就会一直变差,如果等到某个输入,就会获得奖励.可以用nice值来决定优先级.我们可以用nice命令设置进程的nice值,也可以使用renice命令来调整他的值.比如说要对进程ID为1136的进程重新调整nice值,可以 这么运行 renice 10 1136,这将把1136的nice值增加10.
3.启动新进程.
我们可以在一个程序的内部启动另一个程序,这个可以简单的通过库函数system 来完成.
#include<stdlib.h>
int system(const char *string);
运行字符串的命令.命令的执行情况如同在shell中执行以下命令:
sh -c 命令 。system函数一般用处不大,因为它需要启动新的shell来运行程序,这个对环境依赖大,而且也不理想。一般我们用以下函数来启动进程。
#include<unistd.h>
char **environ;
int execl(const char *path,const char *arg0,...,(char *)0);
int execlp(const char *file,const char *arg0,...,(char *)0);
int execle(const char *path,const char *arg0,...,(char *)0,char *const envp[]);
int execv(const char *path,char *const argv[]);
int execvp(const char *file,char *const argv[]);
int execve(const char *path,char *const argv[],char *const envp[]);
这些函数可以分为两类,其中execl,execlp,execle支持可变参数。参数用一个空指针结束。execv和execvp第二个参数是一个字符串数组。不管哪种情况,新程序在启动时会把在argv数组中给定的参数传递给main函数。
这些函数通常是用execve实现的。虽然并不是必须要这么做。
以字符P结尾的函数通过搜索PATH环境变量来查找新程序中的可执行文件的路径。如果可执行文件不再PATH定义的路径中,我们就需要把包括目录在内的使用绝对路径的文件名作为参数传递给函数。
全局变量environ可用来把一个值传递到新的程序环境中。此外,函数execle和execve可通过参数envp传递字符串数组作为新程序的环境变量。
如果想通过exec函数来启动ps程序,我们可以这么写。
#include<unistd.h>
char *const ps_argv[] = {"ps“,”ax“,0};
char *const ps_envp[] = {"PATH=/bin:/usr/bin","TERM=console“,0};
execl("/bin/ps","ps","ax",0);
execlp("ps","ps","ax",0);
execle("/bin/ps","ps","ax",0,ps_envp);
execv("/bin/ps",ps_argv);
execvp("ps",ps_argv);
execve("/bin/ps",ps_argv,ps_envp);
这里需要注意的是,当我们用exec函数执行时,一般不会有返回,除非发生了错误。他的进程PID,PPID,和nice值都跟原先的一样。但是exec函数执行完毕之后,不会在返回原来调用他的函数了。这点跟fork不一样。所以exec是 替换进程映像,而fork是复制进程映像。
至于fork这个就不需要多说了。子进程返回0,父进程返回子进程ID。
等待一个进程,可以在父进程中调用wait来等待子进程的结束。
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int *stat_loc);
如果stat_loc不是空指针,状态信息会写入它所指的位置。我们可以用sys/wait.h文件中定义的宏来解释状态信息。 这个具体我就不打了,用的的时候百度。
当然,还有一个waitpid系统调用来等待子进程的结束。
#include<sys/types.h>
#include<sys/wait.h》
pid_t waitpid(pid_t pid,int *stat_loc,int options);
4.僵尸进程。
这尼吗听起来这么那么吓人。草。其实意思就是说,我们一个进程已经不再运行了,但是却要等待另外一个进程的结束,这个进程才能结束。而假设说那个进程突然间异常了,那这个不在工作的进程也就结束不了,只有等到init来清理他们。这就是僵尸进程。
5.假设说,我们有一个程序,它将文本中所有小写完全转换为大写。那么我们在另一个程序中要怎么调用这个程序呢?这里给出一个简单示例:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
char *filename;
if(argc != 2)
{
exit(1);
}
filename = argv[1];
if(!freopen(filename,"r",stdin))
{
exit(2);
}
execl("./upper","upper",0);
//注意,如果exec没有发生错误,下面这句将不会执行。
perror("could not exec ./upper");
exit(3);
}
6.信号。
信号的名称在头文件signal.h中定义。
程序可以用signal库函数来处理信号。定义如下:
#include<signal.h>
void (*signal(int sig,void (*func)(int)))(int);
这个狗血的函数说明。signal是带有sig和func两个参数的函数。准备捕获或者忽略的信号由参数sig给出,接收到指定的信号后将要调用的函数有参数func给出。其中signal函数本身也返回一个同类型的函数。即先前用来处理这个信号的函数,或者也可以用SIG_IGN(忽略信号)和SIG_DFL(恢复默认行为),两个之一来替代.
当然了,如今的程序已经不再推荐用signal了建议不要使用.而使用更可靠的sigaction来实现.
7.发送信号.
#include<sys/types.h>
#include<signal.h>
int kill(pid_t pid,int sig);这个函数把参数sig给定的信号发送给有参数pid给出的进程号所制定的进程.当然,需要一定的权限.否则将失败返回-1.
8.sigaction一个健壮的信号接口
#include<signal.h>
int sigaction(int sig,const struct sigaction *act,strucct sigaction *oact);
这个好像有点小复杂...到时候在研究研究.
十一章结束,有点小失落,如果给我重新来过大学,我一定不会像现在这样子.可是世事难料,奈何?就这样吧.
爱生活,爱编程.
Linux进程与信号详解
本文详细介绍了Linux系统中进程的概念、进程的启动方法、进程调度、僵尸进程等问题,并讲解了如何使用信号处理进程间的通信。

被折叠的 条评论
为什么被折叠?



