进程
1、进程标识符 pid
类型 pid_t
命令 ps
进程号是顺次向下使用
getpid();
getppid();
2、进程的产生
(1)fork();
注意理解关键字:duplicating 意味着拷贝、克隆、一模一样等含义
fork后父子进程的区别:fork的返回值不一样,pid不同,ppid不同,未决信号和文件锁不继承,资源利用量归0.
init进程:1号,是所有进程的祖先进程。
2022.1.3
1、永远不要猜测父子进程谁先调度,调度器的调度策略来决定哪个进程先运行。
2、ps axf 调用之后 可以查看到进程关系,顶格写的才是1号init进程。
3、刷新所有成功打开的流。
(2)vfork();
读时共享,写时拷贝,基本被废弃了,被整合到了fork。
进程创建实例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
__pid_t pid;
/*1、永远不要猜测父子进程谁先调度,调度器的调度策略来决定哪个进程先运行*/
printf("[%d]Begin!\n",getpid());
/*3、刷新所有成功打开的流*/
fflush(NULL);/*!!!在Begin之后没来得及放入全缓冲区文件中,就fork一次,因此会输出2次Begin*/
pid = fork();
if (pid<0)
{
perror("fork()");
exit(1);
}
if (pid == 0) //child
{
printf("[%d]:child is working!\n",getpid());
}
if (pid > 0) //parent
{
printf("[%d]:parent is working!\n",getpid());
}
/*2、ps axf 调用之后 可以查看到进程关系,顶格写的才是1号init进程*/
//getchar();
printf("[%d]End!\n",getpid());
exit(0);
}
质数版本1—进程的创建fork
僵尸未收尸,变成孤儿进程,被init接管。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define LEFT 30000000
#define RIGHT 30000200
int main()
{
long long i,j,mark;
__pid_t pid ;
for (i = LEFT; i <=RIGHT; i++)
{
pid = fork();
if (pid<0)
{
perror("fork()");
exit(1);
}
if (pid == 0) //child
{
mark = 1;
for (j = 2; j < i/2; j++)
{
if (i%j == 0)
{
mark = 0;
break;
}
}
if (mark)
printf("%lld is a primer\n",i);
//sleep(1000);//父进程退出,子进程全部变成孤儿进程,init接管孤儿进程。
exit(0);//进程结束
}
}
sleep(1000);
exit(0);
}
3、进程的消亡及释放资源
wait();//死等,阻塞性 相当于wait(-1,&status,0);的封装
waitpid(pid_t pid,int *status,int options);//有options可以让waitpid成为非阻塞模式。
分块法:把需要的200个进程分为N份。
进程分配之交叉分配法的实现。
一般交叉分配法比分块法更优秀。
waitid();
wait3();
wait4();
质数版本2—线程的回收wait
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#define LEFT 30000000
#define RIGHT 30000200
int main()
{
int i,j,mark;
__pid_t pid ;
for (i = LEFT; i <=RIGHT; i++)
{
pid = fork();
if (pid<0)
{
perror("fork()");
exit(1);
}
if (pid == 0) //child
{
mark = 1;
for (j = 2; j < i/2; j++)
{
if (i%j == 0)
{
mark = 0;
break;
}
}
if (mark)
printf("%d is a primer\n",i);
//这里必须要exit(0),否则系统一直创建进程,直到创建满为止
exit(0);//进程结束,退出进程
}
}
for (i = LEFT; i <= RIGHT; i++)
wait(NULL);//不关心回收进程的状态,直接全部收尸。
exit(0);
}
质数版本3–交叉分配法
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#define LEFT 30000000
#define RIGHT 30000200
#define N 3
int main()
{
int i,n,j,mark;
__pid_t pid ;
//创建N个进程
for (n = 0; n < N; n++)
{
pid = fork();
if (pid<0)
{
perror("fork()");
exit(1);
}
if (pid == 0)
{
for (i = LEFT+n; i <=RIGHT; i+=N)
{
mark = 1;
for (j = 2; j < i/2; j++)
{
if (i%j == 0)
{
mark = 0;
break;
}
}
if (mark)
printf("[%d] %d is a primer\n",n,i);
}
exit(0);//进程结束
}
}
for (n = 0; n <N; n++)
wait(NULL);
exit(0);
}
4、exec函数族
execl();
execlp();
execle();
execv();//变参函数
execvp();//变参函数
注意fflush();
exec函数实例
pid不变。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{
puts("Begin!");
/*在exec之前,刷新缓冲区*/
fflush(NULL);
execl("/bin/date","date","+%s",NULL);
perror("execl()");
exit(1);
puts("End!");
exit(0);
}
fork,exec,wait联合说明
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{
pid_t pid;
puts("Begin!");
fflush(NULL);
pid = fork();
if (pid<0)
{
perror("fork()");
exit(1);
}
if (pid == 0)
{
execl("/bin/date","date","+%s",NULL);
perror("execl()");
}
wait(NULL);
puts("Begin!");
exit(0);
}
自制shell–P174–命令实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#include <glob.h>
#define DELIMS " \t\n"
struct cmd_st
{
glob_t globres;
};
static void prompt(void)
{
printf("mysh-0.1$");
}
static void parse(char *line,struct cmd_st *res)
{
char *tok;
glob_t globres;
int i = 0;
while (1)
{
tok = strsep(&line,DELIMS);
if (tok == NULL)
break;
if (tok[0] == '\0')
continue;
glob(tok,GLOB_NOCHECK|GLOB_APPEND*i,NULL,&res->globres);
i = 1;
}
}
int main()
{
char *linebuf = NULL;
size_t linebuf_size = 0;
glob_t globres;
struct cmd_st cmd;
pid_t pid;
while (1)
{
prompt();
if(getline(&linebuf,&linebuf_size,stdin))
break;
parse(linebuf,&cmd);
if (0)//内部命令
{
}
else //外部命令
{
pid = fork();
if(pid<0)
{
}
if(pid==0) //children
{ execvp(cmd.globres.gl_pathv[0],cmd.globres.gl_pathv);
perror("execvp()");
exit(1);
}
else //parent
{
wait(NULL);
}
}
}
exit(0);
}
5、用户权限以及组权限(u+s,g+s)
如果一个可执行文件拥有u+s 权限,那么当别的用户调用当前可执行权限的文件,它的权限会变成当前user权限来执行。
如果一个可执行文件拥有g+s 权限,那么当别的用户调用当前可执行权限的文件,它的权限会变成当前同组身份权限来执行。
!!!慎重下放权限。
getuid();//获取当前进程id
geteuid();//获取当前进程有效id
getgid();//获取当前进程组id
getegid();//获取当前进程有效组id
setuid();//设置进程id
setgid();//设置进程组id
setreuid();//交换real effective uid(原子化的交换)
setregid();//交换real effective gid(原子化的交换)
seteuid();//更改有效用户id
setegid();//更改有效组id
自制sudo—P177,10min
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#include <glob.h>
int main(int argc,char **argv)
{
pid_t pid;
if (argc < 3)
{
fprintf(stderr,"Usage...\n");
exit(1);
}
pid = fork();
if (pid < 0)
{
perror("fork()");
exit(1);
}
if (pid == 0)//子进程
{
setuid(atoi(argv[1]));//设置有效id
execvp(argv[2],argv+2);//变参execvp
perror("execvp()");
exit(1);
}
if (pid > 0)
{
}
exit(0);
}
6、观摩课:解释器文件(脚本文件)
脚本文件
#!/bin/cat
ls
whoami
ps
7、system()
理解成 fork、exec和wait的封装
系统函数0–执行一个shell命令
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
system("date +%s > /tmp/out");
exit(0);
}
系统函数1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{
pid_t pid;
pid = fork();
if (pid<0)
{
perror("fork()");
exit(1);
}
if (pid == 0)//子进程执行操作
{
execl("/bin/sh","sh","-c","date","+%s",NULL);
perror("execl()");
}
wait(NULL);
exit(0);
}
8、进程会计
acct();进程结束填充字段、不可移植
9、进程时间
times();获取进程时间,结构体。
10、守护(精灵)进程
会话 session(),标识 sid
终端
setsid(); //只能是非leader 的进程调用
getpgid();
setpgid();
单实例守护进程:锁文件 /var/run/name.pid
启动脚本文件:/etc/rc*...
守护进程日志实例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <glob.h>
#include <syslog.h>
#include <errno.h>
#define FNAME "tmp/out"
static int daemonize()
{
pid_t pid;
int fd;
pid = fork();
if (pid<0)
return -1;
if (pid>0) //parent
{
exit(0);
}
fd = open("/dev/null",O_RDWR);
if (fd<0)
return -1;
dup2(fd,0);
dup2(fd,1);
dup2(fd,2);
if (fd > 2)
close(fd);
setsid();
chdir("/");
return 0;
}
int main()
{
FILE *fp;
int i;
if (daemonize())
{
exit(1);
}
else
{
}
fp = fopen(FNAME,"w");
if (fp == NULL)
{
perror("fopen()");
exit(1);
}
for (i = 0; ; i++)
{
fprintf(fp,"%d\n",i);
fflush(fp);
sleep(1);
}
fclose(fp);
closelog();
exit(0);
}
11、系统日志书写
syslog服务
openlog()
syslog()
closelog()
进程日志实例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <glob.h>
#include <syslog.h>
#include <errno.h>
#define FNAME "tmp/out"
static int daemonize()
{
pid_t pid;
int fd;
pid = fork();
if (pid<0)
return -1;
if (pid>0) //parent
{
exit(0);
}
fd = open("/dev/null",O_RDWR);
if (fd<0)
return -1;
dup2(fd,0);
dup2(fd,1);
dup2(fd,2);
if (fd > 2)
{
close(fd);
}
setsid();
chdir("/");
return 0;
}
int main()
{
FILE *fp;
int i;
openlog("mydaemon",LOG_PID,LOG_DAEMON);
if (daemonize())
{
syslog(LOG_ERR,"daeonize() failed!");
exit(1);
}
else
{
syslog(LOG_INFO,"daemonize() successded!");
}
fp = fopen(FNAME,"w");
if (fp == NULL)
{
syslog(LOG_ERR,"fopen():%s",strerror(errno));
exit(1);
}
syslog(LOG_INFO,"%s was opened.",FNAME);
for (i = 0; ; i++)
{
fprintf(fp,"%d\n",i);
fflush(fp);
syslog(LOG_DEBUG,"%d is printed",i);
sleep(1);
}
fclose(fp);
closelog();
exit(0);
}