linux下实现多线程有两种函数调用:一种是通过pthread.h里面已经封装好的函数调用,另一种是通过unistd.h里面的fork函数调用。前面已经已经列举了pthread的使用,下面来书fork的例子。

一.fork函数

简单的fork例子

#include

#include

#include

using namespace std;

int main()

{

pid_t pid;

pid=fork();

cout<

return 0;

}

输出:

fork()

fork()

可以看出,从pid=fork()之后开始,后面的输出语句父子进程都会执行一次。

再看例子:

#include

#include

#include

using namespace std;

int main()

{

pid_t pid;

switch(pid=fork())

{

case 0 :cout<

case -1:cout<

default:cout<

}

return 0;

}

输出:

parent:9743

child:0

fork函数执行成功时会分两次返回pid,其中一次在父进程里面返回,得到的pid是子进程的进程标识符;一次在子进程里面返回,得到的pid是0。所以可以根据pid来区分父子进程,来执行不同的操作。

fork函数执行失败时会返回-1.

二。系统调用 exec

产生子进程之后可以通过exec系列函数执行其他功能程序。

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

简单的execl例子

#include

#include

using namespace std;

int main()

{

cout<

execl("/bin/date","date","-d","2012/12/12",NULL);

cout<

return 0;

}

输出:

开始执行

2012年 12月 12日 星期三 00:00:00 CST

execl参数介绍:

第一个参数 path 给出了被执行的程序所在的文件名,它必须是一个有效的路径名,文件本身也必须含有一个真正的可执行程序。

第二个以及用省略号表示的其它参数一起组成了该程序执行时的参数表。

其中,参数表的第一项是不带路径的程序文件名。最后要用一个 null 指针来标记参数表的结尾。

结合fork的例子

#include

#include

#include

using namespace std;

int main()

{

pid_t pid;

switch(pid=fork())

{

case 0 :

{

cout<

execl("/bin/date","date","-d","2012/12/12",NULL);//执行execl调用

cout<

}

case -1:cout<

default:cout<

}

return 0;

}

输出:

parent!

child!

2012年 12月 12日 星期三 00:00:00 CST

三.父进程与子进程的关联

在fork之后exec之前,两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。所以子进程中的所有变量均保持它们在父进程中之值(fork()的返回值除外)。

当父子进程中有更改相应段的行为发生时,再为子进程相应的段分配物理空间,如果不是因为exec,内核会给子进程的数据段、堆栈段分配相应的物理空间(至此两者有各自的进程空间,互不影响),而代码段继续共享父进程的物理空间(两者的代码完全相同)。而如果是因为exec,由于两者执行的代码不同,子进程的代码段会分配单独的物理空间。

文件描述符的继承

在父进程中已打开的文件,在子进程中也已被打开,子进程支持这些文件的文件描述符。但是文件指针则是为两个进程共用

如果设置了执行关闭位(close-on-exec)的话,调用 exec 时会关闭相应的文件。该位的默认值为非设置。

文件指针示例

#include

#include

#include

#include

#include

using namespace std;

int main()

{

int fd;

int pid;

char buf[1]={'\0'};

if ((fd=open("data.txt",O_RDONLY))<0)

{//data里面仅有两个字符‘1’和‘2’

perror("open failed");

exit(1);

}

pid=fork();

if (pid<0)

perror("fork failed");

else if (pid==0)

{

read(fd,buf,1);//读取1

cout<

}

else

{

wait(NULL);//读取2

read(fd,buf,1);

cout<

}

}

输出:

1

2

四.进程退出

exit函数

exit()只有一个参数status,称作进程的退出状态,父进程可以使用它的低 8 位。注意,在整型量中,低 8 位在前,高 8 位在后

exit函数示例

#include

#include

#include

#include

using namespace std;

int main()

{

pid_t pid;

switch(pid=fork())

{

case 0 :

{

exit(1);//设置退出状态

break;

}

case -1:cout<

default:

{

int statue;

wait(&statue);

//获取低8位

statue=statue>>8;

statue=statue & 0xff;

cout<

break;

}

}

return 0;

}

输出

1

五.进程同步

wait函数

当子进程执行时,wait函数可以暂停父进程的执行,使起等待。一旦子进程执行完,等待的父进程就会继续执行。如果有多个子进程在执行,那么父进程中的 wait()在第一个子进程结束时返回,恢复父进程执行。通常情况下,父进程调用 fork()后要调用 wait()。

wait示例

#include

#include

#include

#include

#include

#include

using namespace std;

int main()

{

pid_t pid;

switch(pid=fork())

{

case 0 :

{

cout<

break;

}

case -1:cout<

default:

{

switch(pid=fork())

{

case 0 :

{

sleep(1);

cout<<3<

break;

}

case -1:cout<

default:

//产生了两个子进程,但在第一个进程返回时,开始执行

wait(NULL);

cout<<2<

break;

}

}

}

return 0;

}

输出:

1

2

3

六.关于僵尸进程和孤儿进程

在子进程终止时,根据父进程的状态,子进程有两种不同的状态

1.子进程终止时,父进程并不正在执行 wait()调用。

2.当子进程尚未终止时,父进程却终止了。

第一种状态就是所谓的僵尸进程。处于这种状态的进程不使用任何内核资源,但是要占用内核中的进程处理表那一项。直到其父进程执行wait()操作时,把这种处于僵尸状态的进程从系统内删除,子进程才算真正的退出,而其父进程仍将能得到该子进程的结束状态。

在第二种情况中,一般允许父进程结束时,把它的子进程(包括处于僵尸状态的进程)交归系统的初始化进程所属。

僵尸进程示例

#include

#include

#include

#include

using namespace std;

int main()

{

pid_t pid;

switch(pid=fork())

{

case 0 :

{

exit(1);

break;

}

case -1:cout<

default:

{

int statue;

sleep(10);

wait(&statue);

statue=statue>>8;

statue=statue & 0xff;

cout<

break;

}

}

return 0;

}

输出

1

这个示例中,子进程退出时,父进程在sleep,如果此时通过ps查看进程执行会发现一项后缀为 的进程,即僵尸进程。

如果把sleep(10)移到子进程,并将父进程的wait(&statue)注释掉,那么子进程将变为孤儿进程。

七.进程属性

进程标识符

通过函数getpid()可以得到当前进程的进程标识符,getppid()可以得到父进程的进程标识符

进程组标识符

如果一个进程组首结束,则该进程组的全部进程都要被强行终止。系统是根据进程的组标识符来选定应该终止的进程的。

比如,当某个用户退出系统时,则相应的 shell 进程所启动的全部进程都要被强行终止。

int setpgrp(void);设置新的进程组标识符

int getpgrp(void);获得其当前的进程组标识符

环境变量

进程的环境是一个以 NULL 字符结尾的字符串之集合。环境中每个字符串形式:name=something

在使用 environ 指针前,应该首先声明它:extern char **environ;

environ示例:

#include

#include

#include

#include

using namespace std;

extern char** environ;

int main()

{

char** env=environ;

cout<

return 0;

}

输出:

USER=root

八.守护进程

int daemon(int nochdir, int noclose);

1. daemon()函数主要用于希望脱离控制台,以守护进程形式在后台运行的程序。

2. 当nochdir为0时,daemon将更改进程的根目录为root(“/”)。

3. 当noclose为0是,daemon将进程的STDIN, STDOUT, STDERR都重定向到/dev/null。

void daemon()

{

int i:

pid_t pid;

if (pid=fork()) exit(0);/* fork,终止父进程 */

/* 第一子进程 */

setsid();//创建了一个新的进程组,调用进程成了该进程组的首进程

signal(SIGHUP,SIG_IGN);

if (pid=fork()) exit(0);/* fork,终止第一子进程 */

/* 第二子进程 脱离控制终端*/

chdir("/");/* 将工作目录设定为"/" */

umask(0);/* 清除文件掩码 */

/* 关闭所有文件句柄 */

for (i=0;i

{

close(i);

}

}

linux下创建多进程,linux之多进程fork:进程创建相关推荐

  1. Linux下netstat常用,Linux netstat常用命令

    1.统计80端口连接数 netstat -nat|grep -i "80"|wc -l 2.统计httpd协议连接数(查看Apache的并发请求数及其TCP连接状态) ps -ef ...

  2. linux nginx安装php5.5,linux下搭建LNMP(linux+nginx+mysql+php)环境之mysql5.5安装

    linux下搭建LNMP(linux+nginx+mysql+php)环境之mysql5.5安装: 首先安装依赖包: yum -y install gcc gcc-c++ autoconf libjp ...

  3. lnmp php 5.4,linux下搭建LNMP(linux+nginx+mysql+php)环境之php5.4安装

    安装准备:依赖包下载wget http://ah1.down.chinaz.com/201303/PHP-v5.4.13.tar.gz wget http://soft.7dot.com/soft/l ...

  4. Linux多进程开发(三)进程创建之守护进程的学习

       之前发过一篇守护进程的文章,但是解析的不够详细,这次,详细来解释守护进程的一些概念和特性.   概念: 后台运行.没有控制端与之相连的进程.独立于控制终端,通常周期性的执行某种任务.    Wh ...

  5. linux 下C语言编程(2)——进程的创建,挂起,解挂,进程间通信

    在 linux 下利用C语言实现进程的创建,挂起和解挂操作 #include <stdio.h> #include <sys/stat.h> #include <sys/ ...

  6. Linux系统【一】CPU+MMU+fork函数创建进程

    切板中的内容输出到文件### 进程相关概念 程序:编译好的二进制文件,在磁盘上,不占用系统资源(不包括磁盘).(剧本) 进程:占用系统资源,是程序的一次运行.(戏剧) 一个程序可以产生多个进程,一个进 ...

  7. linux 下生成docx,linux下创建、删除文件和文件夹命令.docx

    linux下创建.删除文件和文件夹命令.docx 还剩 6页未读, 继续阅读 下载文档到电脑,马上远离加班熬夜! 亲,喜欢就下载吧,价低环保! 内容要点: 学习 Linux 二(创建.删除文件和文件夹 ...

  8. 关于 Linux fork()进程创建函数 的 执行方式 返回值 lockf锁和并发 控制创建顺序 的探索

    文章目录 BEGIN Demo 1 - 了解fork执行方式 code & result comprehension Demo 2 - fork的返回值研究 code & result ...

  9. linux下终端urvst,Linux中的静态库与动态库

    #什么是库文件? 库文件是事先编译好的方法的合集.比如:我们提前写好一些数据公式的实现,将其打包成库文件,以后使用只需要库文件就可以,不需要重新编写. #Linux系统中: 1.静态库的扩展名为.a: ...

最新文章

  1. Uber无人车撞人视频公布,究竟哪儿出问题了?
  2. Hello Shell
  3. unix awk手册读书笔记
  4. 网络摄像头 登录绕过 RCE漏洞 数据分析报告
  5. Android移动开发之【Android实战项目】DAY6-安卓多线程
  6. react中遇到的问题
  7. CRM and Saptest1 Fiori UI共存的一个典型例子
  8. Vue 2.x 文件夹目录
  9. 采集网页数据生成到静态模板newslist.html文件中(正则表达式)
  10. 简便方法搭建Harbor镜像仓库
  11. Android Multimedia框架总结(十)Stagefright框架之音视频输出过程
  12. ORACLE默认账户及密码
  13. 大华摄像机RTSP断流
  14. 【C#】一文教你搭个简易的Socket服务器
  15. 怎样去掉gif动图水印?在线编辑gif图片技巧
  16. 购买的域名设置域名解析
  17. 嵌入式系统开发15——基于SPI协议的OLED屏显简单应用
  18. 自动驾驶技术基础——GNSS
  19. c语言编程统计学生个数,c编程统计并显示500至800之间所有素数的总个数以及总和...
  20. android app后台收不到消息,不打开智能关怀App收不到手表发的消息

热门文章

  1. 苹果四大供应商向高通索赔90亿;金立否认裁定破产清算
  2. Nginx(二) 虚拟主机配置
  3. Linux内核NAPI机制分析
  4. Win2003利用dfs(分布式文件系统)在负载均衡下的文件同步配置方案
  5. 淘宝宝贝浏览量提升刷新工具 - 最好的淘宝宝贝流量提升工具
  6. 【翻译 windbg - 1】Getting started with windbg - part I (第一部分 1)
  7. Vue.Draggable 实现组件拖拽
  8. mac svn 返回svn upgrade等出错
  9. Javadoc代码追踪记录
  10. 心得 : 面向对象和面向过程的区别