linux 系统编程 进程
进程
进程号一般不重复使用
空闲进程 pid 0 ,内核运行的第一个进程 init pid 1.
内核搜索init的顺序,如果找不到,内核就会发出panic挂起
/sbin/init
/etc/init
/bin/etc
/bin/sh
进程号最大值32768 老unix用16位计算pid,可以在/proc/kernel/pid_max的值修改
#include<sys/types.h>
#include<unistd.h>
Pid_t getpid(); //返回调用进程的pid
Pid_t getppid(); //返回调用进程的父进程pid
1. Exec
#include<unistd.h>
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 execve(const char *path, char *const argv[], char *const envp[]);
Path 指向要调用文件的映像,如路径,arg为第一个参数,一般为文件名,后面接可变参数,最后以NULL结尾。
执行完替换之后,原进程所有数据丢失,原进程设置的信号处理函数和挂起的信号丢失,原进程对线程的设置丢失,进程的统计信息丢失。但进程pid等不变。
详细解释:http://blog.csdn.net/lianghe_work/article/details/47704105
2. fork()
#include<sys/types.h>
#include<ubistd.h>
Pid_t fork();
生成一个和父进程几乎一模一样的进程
不同点:
Pid和ppid
子进程资源统计信息会清零
挂起信号和文件锁不会继承
3. exit
#include<stdlib.h>
Void exit(int status);
Status 标示退出状态 status & 0377会返回给父进程确认
EXIT_SUCCESS 0 EXIT_FAILURE 非零
关闭流程:
在系统中注册的逆序调用atexit或onexit
清空所有已经打开的标准I/O
删除由tmpfile()创建的所有临时文件
调用_exit让内核处理终止进程剩余工作
内核清理:申请的内存,打开的文件,system V信号
进程可以直接调用_exit,但这样一些进程处理的清理未完成,不合理。只有vfork一定要调用_exit。
其他方式结束进程:
Main函数返回或者调用exit(0)。
SIGTERM 和 SIGKILL被触发
程序段错误或者内存耗尽内核强制杀死
4. atexit
#include<stdlib.h>
Int atexit(void (*function) (void));
函数成功返回会将函数注册到进程正常结束的时候调用。
如果进程调用了exec,那么atexit不会被调用,进程被信号结束也不会调用这个函数,被注册的函数应该是无参无返回的,调用顺序和注册顺序相反。
进程结束时,内核会给父进程发送信号SIGCHILD,一般这个信号会被忽略。如果有需要可以使用signal或者sigaction处理
等待死亡的进程会保留一定的信息等待父进程查看,父进程查看后子进程消亡,如果不查看就会成为僵尸进程
5.wait
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int *status);
返回已经终止的子进程 status子进程结束的状态
如果没有子进程结束会阻塞
6.waitpid
#include<sys/types.h>
#include<sys/wait.h>
Pid_t waitpid(pid_t pid,int *status,int options);
Pid 取值
-1 pid绝对值的进程组的所有子进程
0 同一进程组的任意进程
>0 指定的子进程的等待
Options取值:
WNOHANG 不阻塞
实际用户ID 真实的用户ID,无法修改,会在各个地方被继承root可以修改他
有效用户ID 进程使用的用户ID,权限验证使用这个ID,使用setuid可以修改
保存设置的用户ID
文件系统用户ID
#include<sys/types.h>
#include<unistd.h>
Int setuid(uid_t uid); //root用户可以设置任意值,非root设置为实际ID和保存ID
Int setgid(gid_t gid);
Int seteuid(uid_t euid); //同上
Int setegid(gid_t egid);
Int setreuid(uid_t ruid,uid_t euid);
Int setregid(gid_t rgid,gid_t egid);
守护进程:
- fork()创建新的进程,
- 在守护进程父进程中调用exit
- 调用setsid 使得进程有新的进程组和新的会话
- 使用chdir将当前的工作目录改为根目录
- 关闭所有的文件描述符
- 打开0,1,2文件描述符,重定向到/dev/null。
线程:
每个线程都有独占的一个虚拟处理器,独自的寄存器组,指令计数器和处理器状态。
同一进程中的线程共享同一的地址空间(动态内存,映射文件,目标代码等等),打开的文件和其他内核资源。
让出处理器的系统调用
7.Sched_yield();
#include<sched.h>
Int sched_yield();
中断进程,内核会运行新的进程,但是如果没有其他进程就绪,进程会立马恢复,所以一般这个调用没有太大意义。
进程优先级是值越小,优先级越高,开始运行越快,执行时间越长
8.nice
#include<unistd.h>
Int nic(int inc);
成功在现在的优先级上加inc返回新的优先级。只有拥有CAP_SYS_NICE(root)的才能使用负值
由于优先级可以返回负值,所有返回成功失败需要errno测试,在使用前将errno清零
10.getpriority ,setpriority
#include<sys/time.h>
#include<sys/resource.h>
Int getpriority(int which,int who) ;
Int setpriority (int which,int who,int prio) ;
Which 取值:
PRIO_PROCESS PRIO_PGRP PRIO_USER
对应的who
进程id,进程组ID,用户id
只有拥有CAP_SYS_NICE(root)的进程才可以降低nice的值,提高优先级
11.ioprio_get ioprio_set
Int ioprio_get(int which,int who);
Int ioprio_set(int which,int who,int prio);
12 .Getlimit setlimit
#include<sys/time.h>
#include<sys/resource.h>
Struct rlimit{
Rlimit_t rlim_cur; //软限制 内核执行的限制
Rlimit_t rlimit_max;//硬限制
}
Int Getlimit(int resource ,struct rlimit *rlim);
Int setlimit(int resource ,const struct rlimit *rlim);
Resource RLIMIT_CUP
不具备CAP_SYS_NICE(root)的进程只能调低硬限制
RLIMIT_FSIZE
RLIMIT_CORE
RLIM_INFINITY
名称 |
意义 |
RLIMIT_AS |
进程总共可用的内存大小的最大值 |
RLIMIT_CORE |
core文件的最大尺寸,如果为0说明不能创建core文件 |
RLIMIT_CPU |
CPU时间的最大值(单位:秒) |
RLIMIT_DATA |
数据段大小的最大值 |
RLIMIT_FSIZE |
创建文件的大小的最大值 |
RLIMIT_LOCKS |
进程可建立的文件锁的数量的最大值 |
RLIMIT_MEMLOCK |
进程中使用mlock锁定内存的最大尺寸 |
RLIMIT_NOFILE |
进程中文件的打开数量的最大值 |
RLIMIT_NPROC |
每个real user id的子进程数量的最大值 |
RLIMIT_RSS |
最大常驻存储区大小 |
RLIMIT_SBSIZE |
socket缓冲的大小的最大值 |
RLIMIT_STACK |
栈的最大尺寸 |
RLIMIT_VMEM |
=RLIMIT_AS |