LINUX编程学习笔记(十四) 创建进程与 父子进程内存空间
1什么是进程:进程是一个执行中的程序
执行的程序: 代码->资源->CPU
进程有很多数据维护:进程状态/进程属性
所有进程属性采用的一个树形结构体维护
ps -a//所有进程
ps -aue //有效进程
进程状态:(man ps)
D Uninterruptible sleep (usually IO)
R Running or runnable (on run queue)
S Interruptible sleep (waiting for an event to complete)
T Stopped, either by a job control signal or because it is being traced.
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z Defunct ("zombie") process, terminated but not reaped by its parent.
For BSD formats and when the stat keyword is used, additional characters may be
displayed:
< high-priority (not nice to other users)
N low-priority (nice to other users)
L has pages locked into memory (for real-time and custom IO)
s is a session leader
l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do) 多进程
+ is in the foreground process group 前台进程
top
实时查看进程
pstree 查看进程树
kill 向进程发送信号
kill -s 信号 进程ID
kill -l //查看所有信号
kill -s 9 224 //关闭224进程
2 创建进程
1 进程有关的创建函数
1.1 system
int system(const char*filename);
建立一个独立的进程,拥有独立的代码空间
等待新的进程执行完毕,system才返回(阻塞)
使用system调用函数(观察进程ID 观察阻塞)
新进程的返回值和system返回值有关系
1任何进程的返回值不要超过255
2 system中进程的返回值存放在system返回值的8-15位
可以通过printf("%d\n",r>>8 ); 这样来获得返回值
3 linux中有专用的获得返回状态的宏
WEXITSTATUS(status) //#include<wait.h> #include <sys/wait.h>
sys.c
#include <stdio.h>
#include <unistd.h> int main()
{
printf("%d\n",getpid());
sleep(2);
return 254;
} sys2.c
#include <stdio.h>
#include <unistd.h>
#include <wait.h>
#include <sys/types.h>
int main()
{
int r;
printf("%d\n",getpid());
r = system("./sleep");
//printf("%d\n",r>>8 );
printf("%d\n",WEXITSTATUS(r)); }
gcc sys.c -o sleep
gcc sys2.c
./a.out
1.2 popen:创建子进程
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
案例:使用popen调用ls -l 并且建立一个管道读取输出
#include <stdio.h>
#include <unistd.h> int main()
{
FILE *fp = popen("cat file","r"); //注意这里是读取输出,不是打开文件 不能直接写文件名
//FILE *fp = popen("ls -l","r");
if(!fp)
{
perror("popen");
return 1;
} int fd = fileno(fp);
int r;
char buf[1024] = {0};
while((r=read(fd,buf,1023)) > 0)
{
buf[r] = 0;
printf("%s",buf);
}
pclose(fp); }
1.3 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[]);
作用: 替换当前代码空间中的数据
函数本身不创建新的进程
第一个参数:替换的程序
第二个参数:
命令行
命令行格式:命令名 选项参数 NULL
命令行结尾必须是空字符串
execl execlp的区别:
execl 只在当前路径搜索
execlp 可以使用系统搜索路径(which能找到)
如果都找不到,可以使用绝对路径
命令锁指向的程序 命令本身 参数列表
如果返回-1 失败
#include <stdio.h> int main()
{
int r = execl("/bin/ls","ls","-l",0); // 只能调用当前路径
// int r = execlp("ls","ls","-l",0);// 能调用系统路径
printf("调用结束%d\n",r);
return 0;
}
1.4 fork
pid_t fork()
1 创建进程
2 新进程的代码是什么:克隆父进程的挨骂
而且克隆来执行的位置
3 在子进程中不调用fork 所有返回值=0
4 父子进程同时执行
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("创建进程前\n");
int pid = fork(); //父进程执行的
while(1)
{
if(pid == 0)
{
printf("子进程 %d\n",getpid());
}
else
{
printf("父进程 %d\n",getpid());
}
}
}
3 应用进程
使用fork实现多任务(unix本身是不支持线程的)
1 进程
2 线程
3 信号
4 异步
5 进程池与线程池
4 理解进程
1父子进程的关系
独立的两个进程
互为父子关系
使用pstree看到
├─gnome-terminal─┬─bash───a.out───a.out //父子关系
│ ├─bash───pstree
│ ├─gnome-pty-helpe
│ └─2*[{gnome-terminal}]
2 问题:
1如果父进程先结束 子进程在么办
子进程将变成孤儿进程,直接依托根进程(init)
孤儿 进程是没有危害的
init─┬─NetworkManager─┬─dhclient
│ └─{NetworkManager}
├─a.out
2 如果子进程先结束 父进程怎么办
子进程先结束,子进程会成为僵尸进程。
僵尸进程的特点: 不占用内存 cpu,但在进程任务管理树上占用一个节点(宝贵)
实际上僵尸进程会造成进程名额的资源浪费。一定要处理僵尸进程
├─gnome-terminal─┬─bash───pstree
│ ├─bash───a.out───a.out
3 僵尸进程使用wait回收(阻塞函数)
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
wait 阻塞直到任意进程结束,status来接收进程返回值,返回值表示返回的进程号
waitpid 阻塞直到指定进程结束
WEXITSTATUS(status) 解析返回值 status的 8-15位是进程的返回值
4 父进程怎么知道子进程退出?
子进程结束时,通常会向父进程发送一个SIGCHLD信号
5父进程处理子进程的信号
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signal 的功能 :
向系统注册,只要接收到信号signal,系统停止进程,执行handler函数,
当函数执行完毕,继续原来的进程 (软中断)
5.1实现处理函数
5.2 使用signal绑定信号与函数
只有当子进程退出时才用wait,因为wait是一个阻塞函数。所以wait和signal一起用。
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
void deal(int s)
{
printf("回收中\n");
sleep(5);
int status;
wait(&status);
printf("回收完毕%d\n",WEXITSTATUS(status));
} int main()
{
printf("创建进程前\n");
int pid = fork(); //父进程执行的
if(pid == 0)
{
printf("子进程 %d\n",getpid());
sleep(5);
return 88;
}
else
{ printf("父进程 %d\n",getpid());
signal(SIGCHLD,deal);
while(1)
{
sleep(1);
printf("parent\n");
}
return 0;
}
}
zhao@ubuntu:~/unix/5$ ./a.out
创建进程前
父进程 2324
子进程 2325
parent
parent
parent
parent
回收中
回收完毕88
parent
parent
parent
^C
6 父子进程的内存空间
6.1全局变量 局部变量 堆变量 都会被子进程拷贝,但与原先的独立。
注意 堆内存被复制了,需要分别在各个进程中手动释放。
子进程克隆了父进程的全局区和局部区内存,但内存区域指向不同的物理空间。
尽管克隆但内存独立,不能相互访问。
进程间通信(IPC)是大问题。
6.2 内存映射与子进程:
内存映射的属性,决定子进程和父进程是否映射在同一物理空间。
MAP_SHARED: 映射到同一物理空间。 (改一个进程中的,其他进程的也变化)
MAP_PRIVATE:映射到不同的物理空间。
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h> int main()
{
int *a = mmap(0,4,PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_SHARED,0,0);
*a = 20;
int pid = fork(); //父进程执行的
if(pid == 0)
{
*a= 90;
printf("parent :a=%d\n",*a);//90
}
else
{
sleep(3);
printf("child :a=%d\n",*a);//90
} }
因为使用的是MAP_SHARED ,所以射到了同一物理空间, 改动会影响其它的.
若使用MAP_PRIVATE 就可以映射到不同物理空间.
6.3 文件描述符的拷贝
每个进程都维护一个文件描述符列表。
父子进程间,拷贝了文件描述符, 相同文件描述符指向的是同一个文件内核对象。
1 各个进程的文件描述符都需要close。
2 对文件的读写会改变文件对象的读写指针位置,对所有进程都有影响。
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h> int main()
{
int fd = open("test.txt",O_RDWR);
int pid = fork(); //父进程执行的
if(pid == 0)
{
printf("parent:\n");
char buf[1024] ={0};
lseek(fd,0,SEEK_SET);
read(fd,buf,1023);
printf("%s\n",buf);
close(fd);
}
else
{
printf("child:\n");
char buf[1024] ={0};
lseek(fd,0,SEEK_SET);
read(fd,buf,1023);
printf("%s\n",buf);
close(fd);
} }
进程的数据交换,基于两种方式:
内存: 有序/无序:mmap
文件:有序/无序:普通文件
基于内核对象:文件/内存/队列
LINUX编程学习笔记(十四) 创建进程与 父子进程内存空间的更多相关文章
- python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例
python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例 新浪爱彩双色球开奖数据URL:http://zst.aicai.com/ssq/openInfo/ 最终输出结果格 ...
- Linux 编程学习笔记----文档管理系统
本文从网络上完成的第 Linux在文件系统管理. 1.VFS文件系统概述 linux採用VFS来管理文件系统,并且linux设计的原则之中的一个就是everything is file.因此文件管理系 ...
- Linux 编程学习笔记----过程管理和项目发展(在)
转载请注明出处,http://blog.csdn.net/suool/article/details/38406211,谢谢. Linux进程存储结构和进程结构 可运行文件结构 例如以下图: 能够看出 ...
- Linux 编程学习笔记----动笔makefile档
Befroe Beginning. 在设置暑假的plan ,关于Linux的书籍如今在看的是ALP和Linux高级程序设计(杨宗德)第三版.在计划中的是Linux高级环境编程. 如今開始关于Linux ...
- (C/C++学习笔记) 十四. 动态分配
十四. 动态分配 ● C语言实现动态数组 C语言实现动态数组,克服静态数组大小固定的缺陷 C语言中,数组长度必须在创建数组时指定,并且只能是一个常数,不能是变量.一旦定义了一个数组,系统将为它分配一个 ...
- Linux编程学习笔记 -- Process
进程是一个程序的运行. 在一个程序中执行另一个执程序的方法有两种: 1)system 在shell中执行程序 2)fork + exec 复制一个进程,在进程中用新的程序替换原有的程序 for ...
- JavaScript高级程序设计学习笔记第四章--变量、作用域和内存问题
1.变量可能包含两种不同数据类型的值:基本类型值和引用类型值. 基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象. 2.变量复制 如果从一个变量向另一个变量复制基本类型的值,会在 ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十四)之Type Information
Runtime type information (RTTI) allow you to discover and use type information while a program is ru ...
- Linux 编程学习笔记----ANSI C 文件I/O管理
转载请注明出处:http://blog.csdn.net/suool/article/details/38129201 问题引入 文件的种类 依据数据存储的方式不同,能够将文件分为文本文件和二进制文件 ...
随机推荐
- 高斯拉普拉斯算子(Laplace of Gaussian)
高斯拉普拉斯(Laplace of Gaussian) kezunhai@gmail.com http://blog.csdn.net/kezunhai Laplace算子作为一种优秀的边缘检测算子, ...
- javascript操作元素的css样式
我们经常要使用Javascript来改变页面元素的样式.当中一种办法是改变页面元素的CSS类(Class),这在传统的Javascript里,我们一般是通过处理HTML Dom的classname特性 ...
- CLR执行模型 流程总结(图)
如有错误,还望指出:
- MFC常用控件CListCtrl 、CSliderCtrl、CToolTipCtrl、CTreeCtrl的自绘
Window平台下MFC提供的CListCtrl .CSliderCtrl.CToolTipCtrl.CTreeCtrl等控件大多时候是不能满足我们的需求,如果我要在改变滑动条的颜色,我要改变滑动条的 ...
- Eclipse相关集锦第二季
Eclipse相关的问题第二季开始了,这些问题都是我平时遇到的,然后记录下来备忘,帮助到别人最好不过了. 1.Unable to execute dex: GC overhead limit exce ...
- hdu1503
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #inc ...
- Android Studio经常使用操作技巧(不断更新)
这段时间一直在用Android Studio做一些Demo的开发.一開始从Eclipse中转向这个开发工具,各种不适应,希望此博文能够一直更新.还有网友能够分享出自己方便更好更快开发的一些技巧. 首先 ...
- 相遇Qt5
使用Qt5.x版本中的不同方面来开发应用程序,着重于新的Qt Quick的技术,提供了编写C++后端的必要内容,并扩展了Qt Quick. 本章提供了关于Qt5高层次的概述.它对开发者有效的展 ...
- androidstudio 优化gradle编译效率
androidstuido 使用gradle自己主动构建和编译.有时做少量改动编译须要等待时间过长,近期Erik Hellman编写的Boosting the performance for Grad ...
- zTree实现地市县三级级联Action类
zTree实现地市县三级级联Action类 ProvinceAction.java: /** * @Title:ProvinceAction.java * @Package:com.gwtjs.str ...