c++学习笔记(42)

314、调用可执行程序
Linux 提供了 system()函数和 exec 函数族,在 C++程序中,可以执行其它的程序(二进制文件、操
作系统命令或 Shell 脚本)。 一、system()函数
system()函数提供了一种简单的执行程序的方法,把需要执行的程序和参数用一个字符串传给
system()函数就行了。
函数的声明:
int system(const char * string);
system()函数的返回值比较麻烦。
1)如果执行的程序不存在,system()函数返回非 0;
2)如果执行程序成功,并且被执行的程序终止状态是 0,system()函数返回 0;
3)如果执行程序成功,并且被执行的程序终止状态不是 0,system()函数返回非 0。 二、exec 函数族
exec 函数族提供了另一种在进程中调用程序(二进制文件或 Shell 脚本)的方法。
exec 函数族的声明如下:
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 execvpe(const char *file, char *const argv[],char *const envp[]);
注意:
1)如果执行程序失败则直接返回-1,失败原因存于 errno 中。
2)新进程的进程编号与原进程相同,但是,新进程取代了原进程的代码段、数据段和堆栈。
3)如果执行成功则函数不会返回,当在主程序中成功调用 exec 后,被调用的程序将取代调用者程
序,也就是说,exec 函数之后的代码都不会被执行。
4)在实际开发中,最常用的是 execl()和 execv(),其它的极少使用。
示例:
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
int main(int argc,char *argv[])
{
int ret=execl("/bin/ls","/bin/ls","-lt","/tmp",0); // 最后一个参数 0 不能省略。
cout << "ret=" << ret << endl;
perror("execl");
/*char *args[10];
args[0]="/bin/ls";
args[1]="-lt";
args[2]="/tmp";
args[3]=0; // 这行代码不能省略。
int ret=execv("/bin/ls",args);
cout << "ret=" << ret << endl;
perror("execv"); */
}
315、创建进程
一、Linux 的 0、1 和 2 号进程
整个 linux 系统全部的进程是一个树形结构。
0 号进程(系统进程)是所有进程的祖先,它创建了 1 号和 2 号进程。
1 号进程(systemd)负责执行内核的初始化工作和进行系统配置。
2 号进程(kthreadd)负责所有内核线程的调度和管理。
用 pstree 命令可以查看进程树(yum -y install psmisc)。
pstree -p 进程编号
二、进程标识
每个进程都有一个非负整数表示的唯一的进程 ID。虽然是唯一的,但是进程 ID 可以复用。当一个进
程终止后,其进程 ID 就成了复用的候选者。Linux 采用延迟复用算法,让新建进程的 ID 不同于最近终止
的进程所使用的 ID。这样防止了新进程被误认为是使用了同一 ID 的某个已终止的进程。
pid_t getpid(void); // 获取当前进程的 ID。
pid_t getppid(void); // 获取父进程的 ID。 三、fork()函数
一个现有的进程可以调用 fork()函数创建一个新的进程。
pid_t fork(void);
由 fork()创建的新进程被称为子进程。子进是父进程的副本,父进程和子进程都从调用 fork()之后的
代码开始执行。
fork()函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是 0,而父进程的返回值则
是子进程的进程 ID。
子进程获得了父进程数据空间、堆和栈的副本(注意:子进程拥有的是副本,不是和父进程共享)。
fork()之后,父进程和子进程的执行顺序是不确定的。
#include <iostream>
#include <unistd.h>
using namespace std;
int main()
{
int bh=8;
string message="我是一只傻傻鸟。";
pid_t pid=fork();
if (pid>0)
{ // 父进程将执行这段代码。
sleep(1);
cout << "父:pid=" << pid << endl;
cout << "父:亲爱的" << bh << "号:" << message << endl;
}
else
{ // 子进程将执行这段代码。
bh=3; message="你是一只傻傻鸟。";
cout << "子:pid=" << pid << endl;
cout << "子:亲爱的" << bh << "号:" << message << endl;
}
四、fork()的两种用法
1)父进程复制自己,然后,父进程和子进程分别执行不同的代码。这种用法在网络服务程序中很常
见,父进程等待客户端的连接请求,当请求到达时,父进程调用 fork(),让子进程处理些请求,而父进程
则继续等待下一个连接请求。
2)进程要执行另一个程序。这种用法在 Shell 中很常见,子进程从 fork()返回后立即调用 exec。
示例:
#include <iostream>
#include <unistd.h>
using namespace std;
int main()
{
if (fork()>0)
{ // 父进程将执行这段代码。
while (true)
{
sleep(1);
cout << "父进程运行中...\n";
}
}
else
{ // 子进程将执行这段代码。
sleep(10);
cout << "子进程开始执行任务...\n";
execl("/bin/ls","/bin/ls","-lt","/tmp",0);
cout << "子进程执行任务结束,退出。\n";
}
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值