Linux进程线程学习笔记:运行新程序

                           Linux进程线程学习笔记:运行新程序

                                        周银辉

 

在上一篇中我们说到,当启动一个新进程以后,新进程会复制父进程的大部份上下文并接着运行父进程中的代码,如果我们使新进程不运行原父进程的代码,转而运行另外一个程序集中的代码,这就相当于启动了一个新程序。这里的代码我们可以理解成一个可执行程序。

所以,要运行一个新程序,需要最基本的两步:

1,创建一个可运行程序的环境,也就是进程。

2,将环境中的内容替换成你所希望的,也就是用你希望运行的可执行文件去覆盖新进程中的原有映像,并从该可执行文件的起始处开始执行。 

要做到第一点,非常简单,fork函数就可以(参考上一篇) ,要做到第二点,则可以利用exec函数族。

 

exec是一族函数的简称,包含在<unistd.h>中它们作用都一样,用一个可执行文件覆盖进程的现有映像,并转到该可执行文件的起始处开始执行。

原型如下:

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函数为例,其他的大同小异,其第一个参数path是可执行文件的路径,是绝对路径;从arg0参数开始及后面所有的是你要传递给可执行文件的命令行参数,值得注意的是,arg0是可执行文件本身(还记得C语言中老师讲main函数参数列表时所说的么),当然,不传程序本身或传一些乱七八糟的值并不代表不能通过编译或不能运行,只不过,如果可执行文件要用到arg0时会产生一些迷惑;最后有一个注释/*, (char*)0 */是提醒我们最后一个参数应该传空字符串。如何函数运行成功,则不会有任何返回值,否则返回-1,而具体的错误号会被设置在errno,errno是一个全局变量,用于程序设置错误号,跟win32的getLastError函数类似。 

看下面的例子:

#include <stdio.h>
#include <unistd.h>

intmain ()
{
    printf("app start...\n");

    execl("/bin/ls", "/bin/ls", "-l",NULL);

    printf("app end\n");
    
    return0;
}

我们运行了bin目录下的ls程序,参数arg0时ls程序本身路径,arg1为-l,使得其以列表的形式列举当前目录,在我的计算机上程序输出如下:

app start...
total 12
-rw-r--r-- 1zhouyh zhouyh  2732010-09-0611:09temp.c
-rwxr-xr-x 1zhouyh zhouyh 71752010-09-0611:09temp.exe
ls程序运行成功了。但注意到了吗?没有输出“app end”这个字符串,原因很简单,我们没有新起进程,而是直接用ls程序覆盖了main函数所在的进程。


那我们接下来,试着用fork吧,以免影响原进程。

 

#include <stdio.h>
#include <unistd.h>

intmain ()
{
    printf("app start...\n");
    
    if(fork() ==0)
    {
        execl("/bin/ls", "/bin/ls", "-l", NULL);
    }
        
    printf("app end\n");
    
    return0;
}

我们用fork创建了一个新进程,当其成功创建后(返回值为0),我们用execl来加载ls程序并运行之。

程序的输出如下:

app start...
app end
zhouyh@ubuntu:~/Documents$ total 12
-rw-r--r-- 1zhouyh zhouyh  2292010-09-0615:59temp.c
-rwxr-xr-x 1zhouyh zhouyh 72112010-09-0616:00temp.exe

 

程序的所有输出都OK了,但有一点可能和我们想象的不一样,那就是“app end”这个字符串很早就输出了而不是在最后,其实这并没有错,“app end” 是main函数所在的程序(temp.exe)即将结束时输出的,而列举文件目录的ls却完全在另外一个进程中,两个异步执行的进程,他们没有谁先谁后结束可言。

 

如果我们希望所有工作完成之后,即ls也执行玩以后,才输出“app end”,那么可以使用wait 以及waitpid函数,这里简单说一下wait,具体的会在“Linux进程线程学习笔记:进程控制”中讲。
pid_t wait (int * status); //包含在 <sys/wait.h> 中

wait函数讲当前进程休眠,直到该进程的某个子进程结束或者有特定的信号来唤醒。如果子进程正常结束,则讲子进程的进程id(pid)作为返回值,发生错误则返回-1,而status参数讲传出子进程的结束状态值。
针对刚才的例子,可以参考下面的代码:

#include <stdio.h>//for printf(const char)
#include <unistd.h>//for fork()
#include <sys/wait.h>//for wait(int* status)

intmain ()
{
    printf("app start...\n");
    
    if(fork() ==0)
    {
        execl("/bin/ls", "/bin/ls", "-l", NULL);
    }
    
    intstatus;
    wait(&status);
        
    printf("app end\n");
    
    return0;
}

 

程序输出如下:

app start...
total 12
-rw-r--r-- 1zhouyh zhouyh  3372010-09-0616:22temp.c
-rwxr-xr-x 1zhouyh zhouyh 72472010-09-0616:22temp.exe
app end

 

好了,现在回过头来看除execl外的其他几个函数 :

 

int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);

execlp和execl差不多,但区别在于前者会去系统环境变量查找file所指的程序的位置,所以如果通过环境变量能找到可执行文件,则file可以不是绝对路径了,比如 execlp("ls", "ls", "-l", NULL);

 

int execle(const char *path, const char *arg0, ... /*, (char *)0, char *const envp[]*/); 

与execlp不同的是,其最后一个参数作为你自定义的环境变量参数传进去,而不是查找系统环境变量

char *env[] = { "HOME=/usr/home", "LOGNAME=home",(char *)0 };

execle("/bin/ls", "ls", "-l", NULL, env);

 

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[]);

这三个函数和前面的三个类似,函数名由后缀l变成了v,其表达的含义是参数不再用参数列表传递而是用一个参数数组argv[],当然,数组最后一个元素也必须是char* 0 

 

名字这么相近的函数,感觉好容易混淆,那么就从l,v,p,e 这样的后缀来区分吧:
l:参数为一个逗号分隔的参数列表,并以char* 0作为列表结尾

v: 参数为字符串数组,数组的最后一个元素为char* 0

p: 可以通过系统环境变量查找文件位置

e:调用者显示传入环境变量 

 

转载于:https://www.cnblogs.com/zhouyinhui/archive/2010/09/07/1819338.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/263792.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是闭包?闭包的优缺点?

什么是闭包&#xff1f;闭包的优缺点&#xff1f; 闭包&#xff08;closure&#xff09;是javascript的一大难点&#xff0c;也是它的特色。很多高级应用都要依靠闭包来实现。 1、变量作用域 要理解闭包&#xff0c;首先要理解javascript的特殊的变量作用域。 变量的作用域无非…

oracle不同库之间传送文件,EXCEL与ORACLE间的数据互传法数据库 -电脑资料

众所周知&#xff0c;MicrosoftExcel能很直观而方便地进行数据输入&#xff0c;统计&#xff0c;生成图表&#xff0c;但它的数据管理能力有限&#xff0c;对大量的数据查询能力不足&#xff0c;如果利用它数据计算方面的优点和大型 数据库 ORACLE的数据查询优点&#xff0c;可…

使用ANT打包Android应用

大家好&#xff0c;今天来分享一下如何使用ANT打包Android应用。 通常我们习惯用eclipse来开发Android程序&#xff0c;它会自动帮我们打包当前的应用程序。如果在Navigator视图下&#xff0c;我们可以看到以下几个文件&#xff1a; 在上图中&#xff0c;com包放置的是我们的cl…

迷你飞信一出,LibFetion该挂了把

飞信确实是个好东西&#xff01; 发短信不要钱 支持群发&#xff0c;这样发个通知什么的&#xff0c;可以轻松搞定 但是以前的飞信客户端太庞大了 好几十M呢 而且光大还多了很多没有用的功能 比如&#xff1a;什么飞信空间啊&#xff0c;网上营业厅&#xff0c;彩信&#xff0c…

oracle t7-2报价,Sun/Oracle T7-2服务器主板7315607全新7318270原装7318240

Sun/OracleT7-2服务器主板7315607全新7318270原装7318240为便于产品发布和因市场行情随时变动&#xff0c;产品所有信息及价格请以实际咨询为准&#xff01;谢谢&#xff01;&#xff01;Sun/Oracle T7-2服务器主板7315607 System Board Assembly 7318270•530-3510 Interlock …

OSI

OSI&#xff08;开放系统互联(Open System Interconnection)&#xff09; OSI是Open System Interconnection的缩写&#xff0c;意为开放式系统互联。国际标准化组织&#xff08;ISO&#xff09;制定了OSI模型&#xff0c;该模型定义了不同计算机互联的标准&#xff0c;是设计和…

asp.net发送邮件时在正文中插入图片

#region 发送邮件 /// <summary> /// 通过附件发送邮件 /// </summary> /// <param name"emailFrom">发送人邮箱地址</param> /// <param name"files">图片地址</param>/// <param na…

Java设计模式(1)工厂模式(Factory模式)

工厂模式定义&#xff1a;提供创建对象的接口。 为何使用工厂模式 工厂模式是我们最常用的模式了&#xff0c;著名的Jive论坛&#xff0c;就大量使用了工厂模式&#xff0c;工厂模式在Java程序系统可以说是随处可见。为什么工厂模式是如此常用&#xff1f;因为工厂模式就相当于…

cmd使用另一个Oracle的sid,(转发备用)Oracle SID在本机上已经存在,请指定一个不同的SID”的解决办法...

(转发备用)Oracle SID在本机上已经存在,请指定一个不同的SID”的解决办法(2014-04-30 10:57:17)1、 开始&#xff0d;&#xff1e;设置&#xff0d;&#xff1e;控制面板&#xff0d;&#xff1e;管理工具&#xff0d;&#xff1e;服务 停止所有Oracle服务。2、 开始&#xff0…

$Poj1952\ $洛谷$1687\ Buy\ Low,Buy\ Lower$ 线性$DP+$方案计数

Luogu Description 求一个长度为n的序列a的最长下降子序列的长度,以及这个长度的子序列种数,注意相同的几个子序列只能算作一个子序列. n<5000,a[i]不超过long范围 Sol 求最长下降子序列的长度: 1.f[i]表示以a[i]结尾的最长下降子序列长度 2.f[i]表示以i结尾的最长下降子序列…

阻塞和非阻塞通信

同步、异步、阻塞和非阻塞是几种基本的sockets调用方式&#xff0c;也是在进行网络编程时需要理解和区分的基本概念之一。关于这方面的文章和讨论相当丰富&#xff0c;这里着重讨论其中两个比较容易混淆的两个&#xff0c;即非阻塞与异步的关系。 先还是简单所列一下几中调用方…

我和《Visual c++2013入门经典(第7版)》的那些事

前言 笔者今天有幸看到了Visual c2013入门经典&#xff08;第7版&#xff09;&#xff0c;这一本书&#xff0c;回想之前看过些书的2010的版本&#xff0c;陪伴我渡过了漫长的C基础学习之路&#xff0c;下面我将讲述对《Visual c2013入门经典&#xff08;第7版&#xff09;》看…

oracle中的mount是什么意思,oraclenomountmountopen直接的关系

startup nomount startup mount startup open (startup的默认选项) 其他常用的参数&#xff1a;read only ,read write ,force,restrict 这些参数可以一起使用,比如 startup 与 startup open read write 是一样的效果。 Oracle的启动过程&#xff1a;启动实例 - 装载数据库 - 打…

JavaScript中的各种宽高以及位置总结

在javascript中操作dom节点让其运动的时候&#xff0c;常常会涉及到各种宽高以及位置坐标等概念&#xff0c;如果不能很好地理解这些属性所代表的意义&#xff0c;就不能理解js的运动原理&#xff0c;同时&#xff0c;由于这些属性概念较多&#xff0c;加上浏览器之间 实现方式…

C# 制作Com组件:java调用.net DLL的方法

本文将详细为大家介绍一个java调用.net DLL的方法&#xff0c;以实现特殊的客户的特殊要求&#xff1a;“在Java项目中必须使用其提供的用.net写的DLL加密机制&#xff01;” 环境与工具&#xff1a; ◆.net framework 3.5 C# ◆java jdk1.5&#xff0c; Tomcat 5.5 ◆jacob-1.…

MySQL 8.0索引合并

简介参考https://dev.mysql.com/doc/refman/8.0/en/index-merge-optimization.html#index-merge-intersection。索引合并是通过多个range类型的扫描并且合并它们的结果集来检索行的。仅合并来自单个表的索引扫描&#xff0c;而不是跨多个表的索引扫描。合并会产生底层扫描的三种…

linux开通80端口命令,Linux iptables开启80端口

Linux下安装好apache的时候访问IP 发现无法访问!以为安装失败了&#xff0c;于是测试apache 监听的端口80#netstat -lnt |grep 80tcp 0 0 :::80 :::* LISTEN安装成功了&#xff01;想到用本机telnet IP 80不通- - 但…

linux匿名页 文件页,文件页和匿名页

文件页和匿名页文件页内存回收, 也就是系统释放掉可以回收的内存, 比如缓存和缓冲区, 就属于可回收内存. 它们在内存管理中, 通常被叫做文件页 (File-backed Page). 大部分文件页, 都可以直接回收, 以后有需要时, 再从磁盘重新读取就可以了.脏页那些被应用程序修改过, 并且暂时…

第十五周学习总结

学习时间15h      代码行数400行博客数2篇学习内容这周主要做了php大作业的项目&#xff0c;添加了购物车和订单&#xff0c;管理员管理订单的功能&#xff0c;主要运用了session来储存纸&#xff0c;再用session时&#xff0c;必须前面添加session_star();且前面不能有输…

科学家研究:生女有撇步 多钙少碰香蕉

&#xff08;联合早报网讯&#xff09;台湾自由时报报道&#xff0c;科学家研究指出&#xff0c;育龄妇女若想生女孩&#xff0c;应该戒吃香蕉&#xff0c;多吃豆类与硬起司&#xff0c;以及排卵前后数天禁欲&#xff1b;要是能恪守上述规范&#xff0c;日后弄瓦而非弄璋的成功…