7 --- Linux 学习笔记之--进程
2014-08-23 11:36
281 查看
————————————进程————————————————
1. 什么是进程
执行的程序: 代码 资源 CPU
进程有很多数据维护: 进程状态/进程的属性
所有进程属性采用结构体维护: 树形数据结构
ps 查看进程常见属性
top 查看系统进程执行状况
pstree(ptree)
kell 向进程发送信号
kell -s 信号
kell -l 显示进程能接受的所有信号
进程有很多属性: ps 可以查看属性
--------------------------------------------------------------------
$ ps a -------当前用户的所有的进程
$ ps au --------所有的用户
$man ps
$ top ---------查看进程的执行状况(利用空格刷新进程,类似 window 的任务管理器,
q 退出)
$ pstree ----查看进程树 (树状进程)或者 ptree
$ kill -l -----显示进程能接收的所有信号
$ kill -s 9
224(进程号) ----- 关闭进程
---------------------------------------------------------------------
2.创建进程
1. 代码-加载到内存-分配CPU时间片
代码由独立的程序存在。
2. 进程有关的创建函数:
2.1 #include <stdlib.h>
int system(const char *command);
建立独立进程,拥有独立的代码空间。
等待新的进程执行完毕,system 才返回---阻塞
案例:
使用system调用一个程序。
观察进程ID。
观察阻塞。
结论:
新的返回值与system 返回值有关系。
说明:
system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。
返回值
=-1:出现错误
=0:调用成功但是没有出现子进程
>0:成功退出的子进程的id
如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值>。 如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为 system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。
-------------------------------------------------------------------------------------------------------
2.2 子进程: 被创建的进程。
父进程: 相对被创建的进程。
popen: 创建子进程。
在父子进程之间建立管道。
函数说明:
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
popen() 函数通过创建一个管道,调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程。这个进程必须由
pclose() 函数关闭,而不是 fclose() 函数。pclose() 函数关闭标准 I/O 流,等待命令执行结束,然后返回 shell 的终止状态。如果 shell 不能被执行,则 pclose() 返回的终止状态与 shell 已执行 exit 一样。
type参数只能是读或者写中的一种,得到的返回值(标准 I/O 流)也具有和 type 相应的只读或只写类型。如果 type 是 "r" 则文件指针连接到 command 的标准输出;如果 type 是 "w" 则文件指针连接到 command
的标准输入。
command 参数是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到
bin/sh 并使用-c 标志,shell 将执行这个命令。
popen 的返回值是个标准 I/O 流,必须由pclose 来终止。前面提到这个流是单向的。所以向这个流写内容相当于写入该命令的标准输入;命令的标准输出和调用
popen 的进程相同。与之相反的,从流中读数据相当于读取命令的标准输出;命令的标准输入和调用 popen 的进程相同。
popen
通过type是r还是w确定command的输入/输出方向,r和w是相对command的管道而言的。r表示command从管道中读入,w表示 command通过管道输出到它的stdout,popen返回FIFO管道的文件流指针。pclose则用于使用结束后关闭这个指针。
案例:
使用 popen 调用 ls -l ,并且建立一个管道读取输出。
---------------------------------------------------
$ gcc popen.c -omain
$ ./main
& cat test_popen.txt
------------------------------------------
-------------------------------------------------------------------------------------------
2.3 exec 系列函数
#include <unistd.h>
extern char **environ;
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[]);
作用:替换当前进程的代码空间中的代码数据。
函数本身不创建新的进程。
说明:
fork()函数通过系统调用创建一个与原来进程(父进程)几乎完全相同的进程(子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。linux将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。),也就是这两个进程做完全相同的事。
在fork后的子进程中使用exec函数族,可以装入和运行其它程序(子进程替换原有进程,和父进程做不同的事)。
fork创建一个新的进程就产生了一个新的PID,exec启动一个新程序,替换原有的进程,因此这个新的被 exec 执行的进程的PID不会改变(和调用exec的进程的PID一样)。
int execl(const char *path, const char *arg, ...);
第一个参数: 替换程序。
第二个参数……:命令行
命令格式: 命令名 选线参数
案例:使用exec执行一个程序:
体会:
是否创建新的进程? ---- 没有创建新的进程。
execl的参数的命令行格式 ;
execl与execlp的区别; (execl只能是当前路径,execlp使用系统搜索路径)
execl替换当前进程代码。
----------------------------------------------
$gcc text.c -otest
$./test
$gcc exec.c -omain
$./main ---- 和上面的效果一样的
-----------------------------------------------
2.4 fork 函数
#include <unistd.h>
pid_t fork(void);
小案例:
运行结果为:
发现:
这条语句被执行了两次。
结论:
(1).创建了新进程。
(2).新进程的代码是什么?克隆了父进程的代码,而且克隆了执行的位置,
父进程执行的 ,子进程不执行。0是子进程打印的,非0是父进程打印的。。
(3).父子进程同时执行。
3.应用进程:
使用fork创建新的进程有什么意义?
---使用fork实现多任务.
1.进程。
2.线程
3.信号
4.异步
5.进程池与线程池
案例:
进程的主要作用是实现多任务
使用进程创建实现多任务。
1.UI
2.建立多任务框架
显示7为随机数,显示当前时间。
3.分别处理不同的任务。
截图:
查看进程文件是否相同:
--------------------------------------------------------------------------
$ps a----发现两个 main,两个进程号 5419 5420
$ cd /proc
$ls -d 54*
$ cd 5419
$cd fd
$ ls -l
$cd ../../5420/fd
$ls -l
----------------------------------------------------------------------------------------------
4.理解进程。
1.父子进程的关系
有两个目录,所以是两个独立的进程。
互为父子关系。
2.问题:
2.1 父子进程先结束,子进程怎么办?
子进程就是依托根进程init: 变成孤儿进程
孤儿进程没有危害。
2.2 子进程先结束,父进程怎么办?
子进程先结束,子进程会变成僵尸进程
僵尸进程不占用内存,cup,但是进程任务树上有一个节点。
僵尸进程或造成进程名额资源的浪费,所以必须的杀死僵尸进程。
补充:
-------------------------------------------------------------------------------------------------------------------------------------------------------
一个进程在调用 exit 命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进(Zombie)的数据结构(系统调用 exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在
Linux 进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装 SIGCHLD 信号处理函数调用
wait 或 waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么 init 进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。
Linux 系统对运行的进程数量有限制,如果产生过多的僵尸进程占用了可用的进程号,
将会导致新的进程无法生成。这就是僵尸进程对系统的最大危害。
---------------------------------------------------------------------------------------------------------------------------------------------------------
3.僵尸进程使用wait回收
4.父进程怎么知道子进程退出?
子进程结束通常向父进程发送一个信号。 进程编号17
5.父进程处理子进程退出信号
signal(int sig,void(*)(int));
向系统注册:只要sig信号发送,系统停止进程,并调用wait函数
当函数执行完毕,继续原来进程。
5.1 实现处理函数
5.2使用signal 绑定信号 与 函数
僵尸进程回收模型案例:
补充:
对 WIFEXITED 这个宏的说明:
1,WIFEXITED(status) 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个
非零值。
(请注意,虽然名字一样,这里的参数 status 并不同于 wait 唯一的参数--指向整数的指针
status,而是那个指针所指向的整数,切记不要搞混了。
)
2.WEXITSTATUS(status) 当 WIFEXITED 返回非零值时,我们可以用这个宏来提取子进程
的返回值,如果子进程调用 exit(5)退出,WEXITSTATUS(status)就会返回 5;如果子进程调
用 exit(7),WEXITSTATUS(status)就会返回 7。请注意,如果进程不是正常退出的,也就是
说,WIFEXITED 返回 0,这个值就毫无意义。
--------------------------------
————————————————————
$ man scandir
$ man ps
$ man system
$ man wait
$ man 2 wait
$ man popen
$ man execl
$ man rand
$ man 2 time
$ man 2 wait
$ man signal
--------------------------------------------------
问题:
父进程的全局栈,堆,局部栈,fd 也会克隆吗?
6 父进程的资源访问
6.1 内存资源
6.2 文件资源
说明: 子进程克隆了父进程的整个内存区域(全局区/局部区,内存),但是内存区域指向不同的物理空间。
尽管克隆,但是内存独立,不能相互访问。
映射内存:
MAP_SHARED(公有): 映射到同一个物理内存。
MAP_PRIVATE(私有):映射到不同的物理内存。
1. 什么是进程
执行的程序: 代码 资源 CPU
进程有很多数据维护: 进程状态/进程的属性
所有进程属性采用结构体维护: 树形数据结构
ps 查看进程常见属性
top 查看系统进程执行状况
pstree(ptree)
kell 向进程发送信号
kell -s 信号
kell -l 显示进程能接受的所有信号
进程有很多属性: ps 可以查看属性
--------------------------------------------------------------------
$ ps a -------当前用户的所有的进程
$ ps au --------所有的用户
$man ps
$ top ---------查看进程的执行状况(利用空格刷新进程,类似 window 的任务管理器,
q 退出)
$ pstree ----查看进程树 (树状进程)或者 ptree
$ kill -l -----显示进程能接收的所有信号
$ kill -s 9
224(进程号) ----- 关闭进程
---------------------------------------------------------------------
2.创建进程
1. 代码-加载到内存-分配CPU时间片
代码由独立的程序存在。
2. 进程有关的创建函数:
2.1 #include <stdlib.h>
int system(const char *command);
建立独立进程,拥有独立的代码空间。
等待新的进程执行完毕,system 才返回---阻塞
案例:
使用system调用一个程序。
观察进程ID。
观察阻塞。
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> main() { int r; printf("%d\n",getpid()); //r = system("./text"); //r = system("ls -l"); //r = system("gcc text.c -otext"); r = system("make"); //printf("%d\n",r>>8 & 255) printf("%d\n",WEXITSTATUS(r)); }
结论:
新的返回值与system 返回值有关系。
说明:
system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。
返回值
=-1:出现错误
=0:调用成功但是没有出现子进程
>0:成功退出的子进程的id
如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值>。 如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为 system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。
-------------------------------------------------------------------------------------------------------
2.2 子进程: 被创建的进程。
父进程: 相对被创建的进程。
popen: 创建子进程。
在父子进程之间建立管道。
函数说明:
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
popen() 函数通过创建一个管道,调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程。这个进程必须由
pclose() 函数关闭,而不是 fclose() 函数。pclose() 函数关闭标准 I/O 流,等待命令执行结束,然后返回 shell 的终止状态。如果 shell 不能被执行,则 pclose() 返回的终止状态与 shell 已执行 exit 一样。
type参数只能是读或者写中的一种,得到的返回值(标准 I/O 流)也具有和 type 相应的只读或只写类型。如果 type 是 "r" 则文件指针连接到 command 的标准输出;如果 type 是 "w" 则文件指针连接到 command
的标准输入。
command 参数是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到
bin/sh 并使用-c 标志,shell 将执行这个命令。
popen 的返回值是个标准 I/O 流,必须由pclose 来终止。前面提到这个流是单向的。所以向这个流写内容相当于写入该命令的标准输入;命令的标准输出和调用
popen 的进程相同。与之相反的,从流中读数据相当于读取命令的标准输出;命令的标准输入和调用 popen 的进程相同。
popen
通过type是r还是w确定command的输入/输出方向,r和w是相对command的管道而言的。r表示command从管道中读入,w表示 command通过管道输出到它的stdout,popen返回FIFO管道的文件流指针。pclose则用于使用结束后关闭这个指针。
案例:
使用 popen 调用 ls -l ,并且建立一个管道读取输出。
// popen.c #include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <stdio.h> int main() { FILE *stream; FILE *wstream; char buf[1024]; memset(buf,0,sizeof(buf));// 初始化buf stream = popen("ls -l","r"); // 将"ls -l"命令输出 wstream = fopen("test_popen.txt","w+");//新建一个可写的文件 fread(buf,sizeof(char),sizeof(buf),stream);//将刚刚FILE* stream的数据流读取到buf中 fwrite(buf,1,sizeof(buf),wstream);//将buf中的数据写到FILE *wstream对应的流中,也是写到文件中 pclose(stream); fclose(wstream); return 0; }
---------------------------------------------------
$ gcc popen.c -omain
$ ./main
& cat test_popen.txt
------------------------------------------
-------------------------------------------------------------------------------------------
2.3 exec 系列函数
#include <unistd.h>
extern char **environ;
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[]);
作用:替换当前进程的代码空间中的代码数据。
函数本身不创建新的进程。
说明:
fork()函数通过系统调用创建一个与原来进程(父进程)几乎完全相同的进程(子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。linux将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。),也就是这两个进程做完全相同的事。
在fork后的子进程中使用exec函数族,可以装入和运行其它程序(子进程替换原有进程,和父进程做不同的事)。
fork创建一个新的进程就产生了一个新的PID,exec启动一个新程序,替换原有的进程,因此这个新的被 exec 执行的进程的PID不会改变(和调用exec的进程的PID一样)。
int execl(const char *path, const char *arg, ...);
第一个参数: 替换程序。
第二个参数……:命令行
命令格式: 命令名 选线参数
案例:使用exec执行一个程序:
体会:
是否创建新的进程? ---- 没有创建新的进程。
execl的参数的命令行格式 ;
execl与execlp的区别; (execl只能是当前路径,execlp使用系统搜索路径)
execl替换当前进程代码。
// text.c #include <stdio.h> #include <unistd.h> int main() { printf("%d\n",getpid()); sleep(5); return 0; }
////exec.c #include <stdio.h> #include <unistd.h> int main() { int r = execl("test","mytest",NULL);// 这里的test是可执行文件 //int r = execlp("ls","ls","-l",NULL); printf("结束%d\n",r); return 0; }
----------------------------------------------
$gcc text.c -otest
$./test
$gcc exec.c -omain
$./main ---- 和上面的效果一样的
-----------------------------------------------
2.4 fork 函数
#include <unistd.h>
pid_t fork(void);
小案例:
///fork.c #include <stdio.h> #include <unistd.h> int main() { printf("创建进程前!\n"); int pid = fork(); printf("创建进程后:pid = %d\n",pid); return 0; }
运行结果为:
发现:
printf("创建进程后:pid = %d\n",pid);
这条语句被执行了两次。
结论:
(1).创建了新进程。
(2).新进程的代码是什么?克隆了父进程的代码,而且克隆了执行的位置,
父进程执行的 ,子进程不执行。0是子进程打印的,非0是父进程打印的。。
(3).父子进程同时执行。
3.应用进程:
使用fork创建新的进程有什么意义?
---使用fork实现多任务.
1.进程。
2.线程
3.信号
4.异步
5.进程池与线程池
案例:
进程的主要作用是实现多任务
使用进程创建实现多任务。
1.UI
2.建立多任务框架
显示7为随机数,显示当前时间。
3.分别处理不同的任务。
#include <curses.h> #include <unistd.h> #include <time.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <math.h> WINDOW *wtime,*wnumb; main() { initscr(); wtime = derwin(stdscr,3,10,3,(COLS-20)/2); wnumb = derwin(stdscr,3,10,(LINES-3)/2,(COLS-11)/2); box(wtime,0,0); box(wnumb,0,0); refresh(); wrefresh(wtime); wrefresh(wnumb); if(fork()) // parent shot time { time_t tt; struct tm *t; while(1) { tt = time(0); t = localtime(&tt); mvwprintw(wtime,1,1,"%02d:%02d:%02d", t->tm_hour,t->tm_min,t->tm_sec); refresh(); wrefresh(wtime); wrefresh(wnumb); sleep(1); } } else // child shot number { int num = 0; int i; while(1) { // num = rand()%100000000; num = 0; for(i=0;i<7;++i) { num =num*10 + rand()%10; } mvwprintw(wnumb,1,1,"%06d",num); sleep(1); refresh(); wrefresh(wtime); wrefresh(wnumb); } } endwin(); }
截图:
查看进程文件是否相同:
--------------------------------------------------------------------------
$ps a----发现两个 main,两个进程号 5419 5420
$ cd /proc
$ls -d 54*
$ cd 5419
$cd fd
$ ls -l
$cd ../../5420/fd
$ls -l
----------------------------------------------------------------------------------------------
4.理解进程。
1.父子进程的关系
有两个目录,所以是两个独立的进程。
互为父子关系。
2.问题:
2.1 父子进程先结束,子进程怎么办?
子进程就是依托根进程init: 变成孤儿进程
孤儿进程没有危害。
2.2 子进程先结束,父进程怎么办?
子进程先结束,子进程会变成僵尸进程
僵尸进程不占用内存,cup,但是进程任务树上有一个节点。
僵尸进程或造成进程名额资源的浪费,所以必须的杀死僵尸进程。
补充:
-------------------------------------------------------------------------------------------------------------------------------------------------------
一个进程在调用 exit 命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进(Zombie)的数据结构(系统调用 exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在
Linux 进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装 SIGCHLD 信号处理函数调用
wait 或 waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么 init 进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。
Linux 系统对运行的进程数量有限制,如果产生过多的僵尸进程占用了可用的进程号,
将会导致新的进程无法生成。这就是僵尸进程对系统的最大危害。
---------------------------------------------------------------------------------------------------------------------------------------------------------
3.僵尸进程使用wait回收
4.父进程怎么知道子进程退出?
子进程结束通常向父进程发送一个信号。 进程编号17
5.父进程处理子进程退出信号
signal(int sig,void(*)(int));
向系统注册:只要sig信号发送,系统停止进程,并调用wait函数
当函数执行完毕,继续原来进程。
5.1 实现处理函数
5.2使用signal 绑定信号 与 函数
僵尸进程回收模型案例:
// signal.c #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> #include <signal.h> void deal(int s) { int status; wait(&status);// status保存状态吗 printf("回收中.....\n"); sleep(5); printf("回收完毕:%d\n",WEXITSTATUS(status)); } void main() { if(fork() == 0) { printf("child!\n"); sleep(4); printf("退出!\n"); exit(8); } else { // 只要sig这个信号到来,就会调用这个函数,回收僵尸进程 signal(SIGCHLD,deal); while(1) { printf("parent!\n"); sleep(1); } } }
补充:
对 WIFEXITED 这个宏的说明:
1,WIFEXITED(status) 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个
非零值。
(请注意,虽然名字一样,这里的参数 status 并不同于 wait 唯一的参数--指向整数的指针
status,而是那个指针所指向的整数,切记不要搞混了。
)
2.WEXITSTATUS(status) 当 WIFEXITED 返回非零值时,我们可以用这个宏来提取子进程
的返回值,如果子进程调用 exit(5)退出,WEXITSTATUS(status)就会返回 5;如果子进程调
用 exit(7),WEXITSTATUS(status)就会返回 7。请注意,如果进程不是正常退出的,也就是
说,WIFEXITED 返回 0,这个值就毫无意义。
--------------------------------
————————————————————
$ man scandir
$ man ps
$ man system
$ man wait
$ man 2 wait
$ man popen
$ man execl
$ man rand
$ man 2 time
$ man 2 wait
$ man signal
--------------------------------------------------
问题:
父进程的全局栈,堆,局部栈,fd 也会克隆吗?
6 父进程的资源访问
6.1 内存资源
6.2 文件资源
说明: 子进程克隆了父进程的整个内存区域(全局区/局部区,内存),但是内存区域指向不同的物理空间。
尽管克隆,但是内存独立,不能相互访问。
映射内存:
MAP_SHARED(公有): 映射到同一个物理内存。
MAP_PRIVATE(私有):映射到不同的物理内存。
相关文章推荐
- linux学习笔记:关于linux守护进程与终端的通信
- Linux内核学习笔记之进程管理2—进程的组织形式
- Linux下学习守护进程的笔记
- Linux 进程调度器学习笔记
- Linux 学习笔记(四)进程控制
- linux学习笔记-读《Linux编程技术详解》-进程与进程环境
- Linux学习笔记---进程
- Linux进程线程学习笔记 系列转
- linux内核学习笔记1——进程的表示
- 学习笔记——操作系统_Linux的进程通信
- linux学习笔记-读《Linux编程技术详解》-守护进程
- [Linux学习笔记]进程概念及控制
- Linux进程线程学习笔记:进程控制
- Linux进程线程学习笔记:进程创建
- Linux进程通信----学习笔记(一)
- Linux进程线程学习笔记:进程创建
- Linux进程线程学习笔记:进程间通信 之 管道
- 嵌入式linux的学习笔记-守护进程(五)
- Linux 学习笔记(八)周期性进程
- 深入LInux内核结构学习笔记---进程表示