进程
1.进程标识符PID
类型 pid_t;命令ps;进程号是顺次向下使用;getpid();getppid();
- ps axf 查看进程树
- ps axm
- ps ax -L
- ps -ef
2.进程的产生
- fork()
- 注意理解关键字: duplicating,意味着拷贝 克隆 一模一样等含义; - fork 后父子进程的区别 : fork 的返回值不一样, pid不同 ,ppid也不同, 未决信号与文件锁不继承,资源利用量清0; - init进程:1号, 是所以进程的祖先进程 pid == 1;调度器的调度策略来决定哪个进程先运行;fflush()的重要性。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("%d start !\n",getpid());
fflush(NULL);//记得刷新 否则begin放到缓冲区 父子进程fork复制的缓冲区里各有一句begin
pid_t pid = fork();
if (pid == 0){
printf("child %d\n",getpid());
}else{
printf("parent %d\n",getpid());
}
getchar();
printf("pid %d end\n",getpid());
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#define LEFT 2
#define RIGHT 200
int main()
{
pid_t pid = 0;
int i,j,mark;
for (i = LEFT;i <= RIGHT;i++){
pid = fork();
if (pid == 0){
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);//记得结束子进程
}
}
getchar();
exit(0);
}
//孤儿进程和僵尸进程
//读时共享,写时复制
- vfork()
3.进程的消亡以及释放资源
- wait();
- waitpid();
- waitid();
- wait3();
- wait4();
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>
#define N 3
#define LEFT 100000002
#define RIGHT 100000200
//分块;交叉分配;进程池
//交叉算法计算 池类算法涉及到竞争
int main()
{
printf("[%d] start !\n",getpid());
fflush(NULL);//记得刷新 否则begin放到缓冲区 父子进程的缓冲区里各有一句begin
pid_t pid = 0;
int i,j,mark;
for (int n = 0;n < N;n++){
pid = fork();
if (pid < 0){
perror("fork");
for (int k = 0;k < n;k++){
wait(NULL);
}
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 is a primer\n",i);
}
}
printf("[%d] exit\n",n);
exit(0);
}
}
int st,n;
for (n =0 ;n < N;n++){
//wait(NULL);
wait(&st);
printf("%d end\n",st);
}
exit(0);
}
//bash:bourne shell
exec函数族
exec 替换 当前进程映像
extern char **environ
- execl();
- execlp();
- execle();
- execv();
- execvpa();
- 注意刷新fflush流;
进程调用一种 exec 函数时,该进程完全由新程序替换,而新程序则从其 main 函数开始执行。因为调用 exec 并不创建新进程,所以前后的进程 ID (当然还有父进程号、进程组号、当前工作目录……)并未改变。exec 只是用另一个新程序替换了当前进程的正文、数据、堆和栈段(进程替换)。
进程间通信:
include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
printf("before exec\n\n");
/* /bin/ls:外部程序,这里是/bin目录的 ls 可执行程序,必须带上路径(相对或绝对)
ls:没有意义,如果需要给这个外部程序传参,这里必须要写上字符串,至于字符串内容任意
-a,-l,-h:给外部程序 ls 传的参数
NULL:这个必须写上,代表给外部程序 ls 传参结束
*/
execl("/bin/ls", "ls", "-a", "-l", "-h", NULL);
// 如果 execl() 执行成功,下面执行不到,因为当前进程已经被执行的 ls 替换了
perror("execl");
printf("after exec\n\n");
return 0;
}
一个小shell
//lhq yyds
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <wait.h>
#include <glob.h>
#include <string.h>
#define BUFSIZE 1024
#define DELIMS " \t\n"
extern char **environ;
static int cd(char *path){
int ret = chdir(path);
if (ret == -1){
perror("chdir");
}
return ret;
}
static void readrc(char *name){
FILE *fp;
fp = fopen(name,"r+");
//处理文件内容
fclose(fp);
}
static void prompt()
{
char pwd[BUFSIZE];
char name[BUFSIZE];
getcwd(pwd,BUFSIZE);
getlogin_r(name,BUFSIZE);
printf("%s %s $ ",name,pwd);
}
static int parse(char *linebuf,glob_t *globres){
char *tok;
int flag = 0;
while (1){
tok = strsep(&linebuf,DELIMS);
if (tok == NULL){
break;
return -1;
}else if(strcmp(tok,"cd") == 0){
char *path = strsep(&linebuf,DELIMS);
return cd(path);
}else if(tok[0] == '\0'){
continue;
}
glob(tok,GLOB_NOCHECK|GLOB_APPEND*flag,NULL,globres);//第一次不能append glob_argv中是随机值 GLOB_NOCHECK | (GLOB_APPEND*flag)==0 第一次不append
flag = 1;
}
return 1;
}
//之后记得 将 ctrl+c 转为 stdout:\n 将ctrl+d 转为 退出+再见标语
int main()
{
printf("This is YSHELL\n");
pid_t pid;
char *linebuf = NULL;
size_t lienbuf_size = 0;
glob_t globres;//解析命令行
//读取配置文件
char *yshrc = "/home/yixingwei/.yshrc";//填一个绝对路径
readrc(yshrc);
while(1){
prompt();
//获取命令
getline(&linebuf,&lienbuf_size,stdin);
//解析命令
int ret = parse(linebuf,&globres);
if (ret == -1){
}else if (ret == 0){//内部命令
}else if (ret == 1){//外部命令
fflush(NULL);
pid = fork();
if (pid < 0){
perror("fork()");
exit(1);
}else if(pid == 0){
execvp(globres.gl_pathv[0],globres.gl_pathv);
perror("execl()");
exit(1);
}
}
waitpid(pid,NULL,0);
}
exit(0);
}
用户权限以及组权限
-
u+s 当其他用户调用该可执行文件时,会切换成当前可执行文件的user的身份来执行
-
g+s
-
uid/gid
- r real
- e effective
函数
- getuid() 返回 real
- geteuid() 返回 effective
// mysudo
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <wait.h>
int main(int argc,char **argv)
{
if (argc < 3){
fprintf(stderr,"Useage");
exit(1);
}
pid_t pid;
pid = fork();
if (pid == 0){
setuid(atoi(argv[1]));
execvp(argv[2],argv+2);
perror("execvp()");
exit(1);
}else {
wait(NULL);
}
exit(0);
}
$ su
# chown root ./mysudo
# chmod u+s ./mysudo
//Linux chown(英文全拼:change owner)命令用于设置文件所有者和文件关联组的命令。利用 chown 将指定文件的拥有者改为指定的用户或组,用户可以是用户名或者用户 ID,组可以是组名或者组 ID,文件是以空格分开的要改变权限的文件列表,支持通配符。 。
$ ./mysudo 0 /etc/shadow
- getgid
- getegid
- setuid 设置effective
- setgid 设置effective
- setreuid 交换 r e //是原子的交换
- setregid 交换 r e
解释器文件
system()
可以理解成 fork+exec+wait 封装
进程会计
- acct()
进程时间
- times()
守护进程
- 会话 sesion 标识是
sid
- 终端
- setsid()
- getpgrp()
- getpgid()
- setpgid()
- 单实例守护进程:锁文件/var/run/name.pid
- 启动脚本文件:/etc/rc*…
系统日志
- syslogd 服务
- openlog
- syslog
- closelog
#include <stdio.h>
#include <stdlib.h>
#include <sys/syslog.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <syslog.h>
#define FNAME "/tmp/out"
static int deamonize(){
int fd;
pid_t pid;
pid = fork();
if (pid < 0){
return -1;
}
if (pid > 0){
exit(0);
}
fd = open("/dev/null",O_RDWR);//输出都忽略
if (fd < 0){
return -1;
}
if (pid == 0){
printf("test");
fflush(NULL);
dup2(fd,0);
dup2(fd,1);
dup2(fd,2);
if (fd > 2){
close(fd);
}
setsid();//脱离终端
//umask();
chdir("/");
}
return 0;
}
int main()
{
FILE* fp;
//开启日志服务
openlog("print i",LOG_PID,LOG_DAEMON);
if (deamonize()){
syslog(LOG_ERR,"init failed!");
}else{
syslog(LOG_INFO,"successded!");
}
fp = fopen(FNAME,"w+");
if (fp == NULL){
syslog(LOG_ERR,"write file failed!");
exit(1);
}
syslog(LOG_INFO,"%s opened",FNAME);
for(int i = 0; ;i++){
fprintf(fp,"%d\n",i);
fflush(NULL);
syslog(LOG_DEBUG,"%d 写入",i);
sleep(1);
}
closelog();
fclose(fp);
exit(0);
}
journalctl _PID=XXX
syslog(LOG_INFO,“successded!”);
}
fp = fopen(FNAME,"w+");
if (fp == NULL){
syslog(LOG_ERR,"write file failed!");
exit(1);
}
syslog(LOG_INFO,"%s opened",FNAME);
for(int i = 0; ;i++){
fprintf(fp,"%d\n",i);
fflush(NULL);
syslog(LOG_DEBUG,"%d 写入",i);
sleep(1);
}
closelog();
fclose(fp);
exit(0);
}
~~~ bash
journalctl _PID=XXX