linux学习之进程控制

首先交代几个基本概念
1.程序:程序是一个存储在磁盘上某个目录中的可执行文件
2.进程:程序的执行实例被称为进程
3.进程ID:每个进程都有一个非负整数型表示的唯一进程ID
除了进程ID,每个进程还有一些其他标识符,下面是相关函数

#include<unistd.h>
pid_t getpid(void);                             返回值:进程的id
pid_t getppid(void);                          返回值:进程父进程的id
uid_t getuid(void);                            返回值:进程实际用户id
uid_t geteuid(void);                          返回值:进程有效用户id
gid_t getgid(void);                            返回值:进程实际组id
gid_t getegid(void);                          返回值:进程有效值id

创建进程
一个现有的进程可以调用fork函数创建一个新进程

#include<unistd.h>
pid_t fork(void); 
返回值:子进程返回0,父进程返回子进程id,出错返回-1

fork函数实例

int main()
{
pid_t pid;
int i=1;
if((pid=fork())<0)                          //创建子进程
{
perror("fork");
}
else if(pid==0)                           //子进程中执行i++
{
i++;
}
else                                         //父进程休眠2s
{
sleep(2);
}


exit(0);


}

fork有以下两种用法
(1)父进程希望复制自己,使子进程和父进程执行不同的代码段。这在网络服务器中是常见的,父进程等待客户端的请求,当请求到来时,父进程调用fork,使子进程处理该请求。父进程则继续等待下一个请求。
(2)一个进程要执行不同的程序,在这种情况下,子进程fork返回后立即调用exex函数族(后面会提到)。

进程的终止
进程有5种正常及3种异常终止方式。5种正常终止方式如下
1)main函数执行return语句。
2)调用exit函数,此操作包括调用各终止处理程序,然后关闭I/O流。不过由于此函数在ISO C中定义,而ISO C并不处理文件描述符,多进程及作业控制,所以对于Linux系统而言,它是不完整的。
3)调用_exit或者 _Exit函数,此函数无需运行终止处理程序。在linux下这两个函数是同义的。_exit函数由exit调用。
4)进程的最后一个线程在其启动例程中执行return语句。
5)进程的最后一个线程调用pthread_exit函数。

3种异常终止如下。
1)调用abort。它产生SIGABRT信号
2)当进程收到某些信号时,调用abort就是一种特例。
3)最后一个线程对“取消”请求做出响应。

不管进程如何终止,最后都会执行内核中同一段代码。这段代码为相应进程关闭所有打开描述符,释放它所用的存储器。
对于父进程已经终止的子进程,它们的父进程全部改为init进程。而父进程是通过wait和waitpid函数来获取子进程的终止状态的。如何父进程没有对已经终止的子进程进行一些处理,例如释放其所占用的资源,则该子进程为僵死进程。

wait和waitpid函数
当一个进程终止时,内核就会向其父进程发送SIGCHLD信号,调用wait和waitpid函数后。
1)如果其所有的子进程还在运行,则阻塞
2)如果子进程已经终止,则立即返回
3)如果没有任何子进程,则出错

#include<sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid,int statloc,int options);
返回值:成功返回进程ID,失败返回0或-1

竞争条件
当多个进程都企图对共享数据进行某种处理,而最后的结果又取决于进程的运行顺序时,我们认为发生了竞争条件。如果在fork之后的某种逻辑显示或隐示地依赖于在fork之后是父进程还是子进程先运行,那么fork函数就会是竞争条件的活跃滋生地。通常我们无法预料哪个进程先运行。即使我们知道哪个先运行,在该进程运行后所发生的事情也依赖于系统负载以及内核的调度算法。
为了避免竞争条件或者是轮询,在多个进程之间需要某种形式的的信号发送和接收的的方法。例如信号机制,有兴趣的可以自己查询书籍,这里就不阐述了。

exec函数族
fork函数是用于创建一个子进程,该子进程几乎是父进程的副本,而有时我们希望子进程去执行另外的程序,exec函数族就提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新程序的内容替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行脚本文件。
这一块内容比较多,有兴趣可以自己查。可以看我另一篇文章
https://blog.csdn.net/slp1994/article/details/83068563

int execl(const char *path, const char *arg, ...)
int execv(const char *path, char *const argv[])
int execle(const char *path, const char *arg, ..., char *const envp[])
int execve(const char *path, char *const argv[], char *const envp[])
int execlp(const char *file, const char *arg, ...)
int execvp(const char *file, char *const argv[])

总而言之对于进程,我们必须熟练掌握的是fork,exec系列,wait,waitpid和_exit函数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值