linux C/C++:进程原语
1. 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
2. 进程环境
在libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明。用以下代码可以查看当前进程的所有环境变量的信息。
#include <stdio.h>
int main(void)
{
extern char **environ;
int i;
for(i = 0; environ[i] != NULL; i++)
printf("%s\n", environ[i]);
return 0;
}
运行结果用键值对的形式展示环境变量的信息。几个常见的环境变量解释:
PATH:可执行文件的搜索路径。
SHELL:当前使用的shell。
HOME:当前用户的主目录路径。
3. 进程状态
4种主要的进程状态:运行、就绪、挂起、终止。
4. 进程原语
在liunx中使用函数fork创建新的进程。
#include <unistd.h>
pid_t fork(void);
函数特点:调用一次,返回两次。
在父进程中,返回创建的子进程的pid;在子进程中返回0;出错,返回-1。
一个创建子进程的实例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
void sys_err(char *s)
{
perror(s);
exit(1);
}
int main(void)
{
pid_t pid;
pid = fork();
if (pid < 0)
sys_err("fork");
else if (pid > 0)
{
/* parent process */
printf("I am parent,my pid is %d, my parent pid is %d\n", getpid(), getppid());
sleep(1); //休眠1秒,防止父进程过早退出
}
else
{
/* child process */
printf("I am child,my pid is %d, my parent pid is %d\n", getpid(), getppid());
}
return 0;
}
//I am child, my pid is 15057, my parent pid is 15056
//I am parent, my pid is 15056, my parent pid is 5292
#include <unistd.h>
#include <sys/types.h> //定义了pid_t、uid_t、gid_t
pid_t getpid(void); //获取当前进程的pid
pid_t getppid(void); //获取当前进程父进程的pid
uid_t getuid(void); //返回实际用户id
uid_t geteuid(void); //返回有效用户id
gid_t getgid(void); //返回实际用户组id
gid_t getegid(void); //返回有效用户组id
所有id都是正数。
父进程和子进程的关系:
1.子进程复制了父进程的PCB(除了pid)和代码段以及数据区。
2.用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
5. exec族
#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., 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的使用,其它的举一反三了:path指出了新可执行程序的路径,后面的arg,即是提供的参数。
使用execl函数更改程序的执行:
//show.c
#include <stdio.h>
int main(int argc, char **argv)
{
int i = 0;
while(i < argc)
printf("%s\n", argv[i++]);
return 0;
}
//app.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
if(argc < 2)
{
fprintf(stderr, "usage:app newapp ...");
exit(1);
}
printf("zhangxiang\n");
//$ argv[1] zx zhangxiangDavid@126.com
execl(argv[1], "zx", "zhangxiangDavid@126.com", NULL); //NULL用于指明参数列表的结束
printf("David\n");
return 0;
}
$ gcc show.c -o show
$ gcc app.c -o app
$ app show
zhangxiang
zx
zhangxiangDavid@126.com
执行printf(“zhangxiang\n”);了后,程序的代码段被替换,所以原程序的printf(“David\n”);不会被执行。
l 命令行参数列表
p 搜素file时使用path变量
v 使用命令行参数数组
e 使用环境变量数组,不使用进程原有的环境变量,设置新加载程序运行的环境变量
这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回,如果调用出错则返回-1,所以exec函数只有出错的返回值而没有成功的返回值。
6. wait()、waitpid()
僵尸进程::子进程退出,父进程没有回收子进程资源(PCB),则子进程变成僵尸进程。
孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为1号进程init进程,称为init进程领养孤儿进程。
子进程结束后,PCB仍然滞留在内存。父进程可以通过子进程的PCB来获知子进程的退出状态:正常退出时的退出码、不正常退出时,是被哪个信号终止的。
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
函数说明:
参数status为传出参数,用于记录退出状态。
当没有子进程退出时,wait调用会阻塞当前进程。
成功,返回子进程的pid;
失败,返回-1;
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid, wpid;
pid = fork();
if(0 == pid)
{
printf("in child\n");
sleep(2);
printf("child exit\n");
}
else if(pid > 0)
{
while(1)
{
wpid = wait(NULL);
printf("in parent %d\n", wpid);
sleep(1);
}
}
else
{
perror("fork");
exit(1);
}
return 0;
}
//in child
//child exit
//in parent 27909
//in parent -1
//in parent -1
//^c
wait()会使父进程阻塞,为了不阻塞,需使用waitpid()
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
函数说明:
pid指明了需回收哪个子进程的PCB;
通过指定options的值,更改函数运行状态。(特别地,指定WNOHANG,将不会阻塞)。
指定WNOHANG,非阻塞后。若没有进程退出,返回0,其它同wait。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid, wpid;
pid = fork();
if(0 == pid)
{
printf("in child\n");
sleep(2);
printf("child exit\n");
}
else if(pid > 0)
{
while(1)
{
wpid = waitpid(0, NULL, WNOHANG);
printf("in parent %d\n", wpid);
sleep(1);
}
}
else
{
perror("fork");
exit(1);
}
return 0;
}
//in parent 0
//in child
//in parent 0
//child exit
//in parent 28700
//in parent -1
//in parent -1
//^c
版权声明:本文为博主原创文章,转载,请注明出处。
原文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/46875181