3、进程
3.1 进程
3.1.1 进程号是按顺序取的,而不是取最小值
/*获取子进程*/
getpid();
/*获取父进程*/
getppid();
3.1.2 fork创建一个新进程
创建的子进程和父进程执行的位置都一样,意味着拷贝、克隆的含义
fork返回值不一样,pid不同、ppid不同、未决信号和文件锁不继承,资源利用量清0
3.1.3 init进程:1号,是所有进程的祖先进程
永远不要凭空猜测哪一个进程先运行
3.1.4 ps axf 可以查看进程的阶梯关系
在fork前一定要加上fflush(NULL)刷新流操作
因为printf类似于全缓冲,\n只代表换行的作用,而不代表刷新的作用了,当第一次printf时Begin还未来得及写入文件时就创建了子进程,因此会有两个Begin。终端上可能只显示一个,但是当./fork > /tmp/out时会输出两个Begin!
printf("[%d]:Begin\n",getpid());
fflush(NULL);/*很重要!!!*/
pid = fork();
fork函数若父子进程同时读一块空间则互不影响,若谁要对同一块空间进行修改,则谁copy一份空间独自对其进行修改
3.1.5 在多进程协作任务时,注意某些子进程需要使用exit(0)以防子进程递归创建导致死机或者资源浪费。
3.1.6 vfork函数使父子进程都使用同一份空间(但此函数基本被弃用)
3.1.7 wait函数
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
wait函数会死等一个进程,属于阻塞状态
waitpid中options可以使其为非阻塞或者阻塞状态
pid>0表示特定的一个pid
pid=0表示收同组的任一子进程
pid=-1表示收任一一个子进程
pid<-1表示从一个进程组收一个pid,此pid为绝对值
3.1.8 进程分配有三种方法
1.分块
2.交叉分配
3.池
3.1.9 exec函数族(一般选execv或者execvp变参更爽)
file或者path为可执行文件
小知识,glob函数也很好用,用man查看即可
1.int ececl(const char *path,const char *arg,...);
2.int ececlp(const char *file,const char *arg,...);
3.int ececle(const char *path,const char *arg,...,const char *envp[]);
4.int ececv(const char *path,const char *argv[]);
5.int ececvp(const char *file,const char *argv[]);
在所有exec函数前必须加fflush(NULL)函数来刷新缓流
如果不加,则输入命令./ex > /tmp/out 和 cat /tmp/out则不会显示Begin!
示例
/*此处头文件省略了嘻嘻嘻*/
int main()
{
puts("Begin!");
fllush(NULL);!!!
execl("/bin/date","date","+%s",NULL);
perror("execl()");
exit(1);
puts("End!");
exit(0);
}
3.2用户组权限相关知识
+s表示在其他用户调用此二进制可执行文件时,这个文件的身份将会变成被调用可执行文件的user来执行(可能是root等用户)
u+s
g+s
getuid();
geteuid();
getgid();
getegid();
setuid();
setgid();
setreuid(uid_t ruid, uid_t euid);原子化的交换
setregid(gid_t guid, gid_t guid);
seteuid();
setegid();
3.3 解释器(shell脚本)
1.#!是脚本文件标记,只会用!后面指定的解释器装载进来,然后用这个指定的解释器解释所有内容,包括第一行,但是第一行会当注释来看待!
1.#!/bin/bash
用bash解释下面所有内容
ls
whoami
cat /etc/shadow
ps
用cat解释下面所有内容
2.#!/bin/cat
ls
whoami
cat /etc/shadow
ps
3.4 进程时间
times获取进程
clock_t times(struct tms *buf);
struct tms
{
clock_t tms_utime/*Usr time*/
clock_t tms_stime/*system time*/
clock_t tms_cutime/*user time of children*/
clock_t tms_cstime/*system time of children*/
};
若想知道每一秒多少个滴答数,可以用宏来检测
sysconf(_SC_CLK_TCK);
3.5 守护进程
1.脱离控制终端(用ps axj查看时TTY为?)
2.是一个会话(session,标识为sid)的leader和进程group的leader
3.前台进程组有且只能有一个,可以没有,后台进程组不能有标准输入、标准输出、标准错误,如果有将会被杀死。
4.setsid();创建一个会话(session)
/只能子进程调用,父进程不能调用(因为父进程为组进程leader),调用这个函数的进程会成为当前新的进程组的leader,并且脱离控制终端/
5.父进程为1号进程
6.单实例守护进程:锁文件一般是/var/run/name.pid,使用锁文件使守护进程具有唯一性
7.启动脚本文件(认为控制):/etc/rc…(不同系统会有区别,也是使其具有唯一性)*
pid_t setsid(void);/*只能子进程调用,父进程不能调用*/
pid_t getpgrp(void);/*返回当前进程所在组的id*/
pid_t getpgid(pid_t pid);/*获取某一个process的组id*/
pid_t setpgid(pid_t pid, pid_t pgid);/*设置某一个process的组id*/
3.6 系统日志
/*syslogd服务*/
void openlog(const char *ident, int option, int facility);/*ident一般是我们给出的字段,option一般放LOG_PID,facility不能随便写,课程内是LOG_DAEMON*/
void syslog(int priority, const char *format, ...);/*提交日志相关信息,类似于printf的操作,一般情况下大于LOG_INFO的才会写进去,LOG_DEBUG这样的不会*/
void closelog(void);