进程:正在执行的程序
命令ps查看进程,pstree查看所有进程
命令top相当于任务管理器,动态变化进程的信息
父子孤尸:
父子进程:父进程可以有多个子进程,一个子进程只能有一个父进程
调度进程:PID =0
孤儿进程:父进程先于子进程结束(一种状态),(老版本)操作系统会为子进程找父进程,即
被init进程收养,init进程又被称为孤儿院进程,(新版本)随机进程收养
僵尸进程:父子进程同时执行,子进程先于父进程结束,子进程还有部分资源在
内存中占用,父进程负责释放,但由于某种原因,父进程并没有回收子进程的终止状态,这时子进程处于僵尸
状态,被称为僵尸进程
进程标识:
当前进程:PID
当前进程父进程:PPID
1.实际用户id(real user id):当前进程的实际调用用户的id
2.有效用户id(effective user id):文件的set_user_id位被关闭,和实际用户id一样;
set_uesr_id开启,为文件拥有者的id,
3.保存的设置用户id(saved set-user-id):程序运行时有效用户id的副本
//各种ID
#include<stdio.h>
#include<unistd.h>
int main(void)
{
printf(" 当前进程ID:%d\n",getpid());
printf(" 父进程ID:%d\n",getppid());
printf(" 实际用户ID:%d\n",getuid());
printf(" 用户组ID:%d\n",getgid());
printf(" 有效用户ID:%d\n",geteuid());
printf("有效用户组ID:%d\n",getegid());
}
tarena:
当前进程ID:88304
父进程ID:76181
实际用户ID:1000
用户组ID:1000
有效用户ID:1000
有效用户组ID:1000
root:su root 命令进入root用户,在root用户编译文件idroot执行
当前进程ID:88339
父进程ID:88321
实际用户ID:0
用户组ID:0
有效用户ID:0
有效用户组ID:0
当设置用户ID:在tarena用户编译
当前进程ID:88375
父进程ID:88343
实际用户ID:1000
用户组ID:1000
有效用户ID:0
有效用户组ID:1000
进程的创建:
fork();
一次创建,两次返回:返回值为子进程的PID和0;
子进程是父进程的不完全副本,除了会复制父进程的数据区、BSS区
、堆区、栈区、参数和环境变量外,包括输入输出缓冲区(内容也会)也会进行复制。
(代码区共享)
fork()函数返回后,系统内核会将父进程维护的文件描述符表也复制到
子进程的进程表项中,但并不复制文件表象。
父进程和子进程共哟个一个文件表象,子进程改变读写位置,父进程也随着改变
setbuf(setout,NULL);//关闭输出缓冲区
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int global = 10;
int main(void)
{
int local = 20;
int * heap = (int*)malloc(sizeof(int));
*heap =30;
printf("进程:%d %p:%d %p:%d %p:%d\n",getpid(),&global,global,&local,local,heap,*heap);
pid_t pid = fork();
if(pid == -1)
{
perror("fork");
return -1;
}
//子进程
if(pid == 0)
{
printf("进程:%d %p:%d %p:%d %p:%d\n",getpid(),&global,++global,&local,++local,heap,++*heap);
return 0;
}
//父进程
sleep(1);
printf("进程:%d %p:%d %p:%d %p:%d\n",getpid(),&global,global,&local,local,heap,*heap);
return 0;
}
进程:90412 0x601068:10 0x7ffd2f3b0528:20 0xe66010:30
进程:90413 0x601068:11 0x7ffd2f3b0528:21 0xe66010:31
进程:90412 0x601068:10 0x7ffd2f3b0528:20 0xe66010:30
//子进程复制父进程的文件描述符表
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main()
{
//父进程打开文件
int fd = open("./shared.txt",O_WRONLY | O_CREAT | O_TRUNC,0777);
if(fd == -1)
{
perror("open");
return -1;
}
//父进程写入hello word
char * a ="hello world!";
if(write(fd,a,strlen(a)) == -1)
{
perror("write");
return -1;
}
//进入子进程
pid_t pid = fork();
if(pid == -1)
{
perror("fork");
return -1;
}
//子进程改变文件读写位置
if(pid == 0)
{
if(lseek(fd,-6,SEEK_END) ==-1)
{
perror("lseek");
return -1;
}
close(fd);
return 0;
}
//父进程写入linux
sleep(1);
char* b ="linux";
if(write(fd,b,strlen(b)) == -1)
{
perror("write");
return -1;
}
close(fd);
return 0;
}
睡眠一秒钟文件内容为hello linux!
进程的终止:正常终止
1、从main函数中返回可令进程终止 return 0;
2、调用exit函数令进程终止 exit(0);//不返回
终止进程前做的事:
A、调用实现通过atexit或on_exit函数注册的退出处理函数;
B、冲刷并关闭所有仍处于打开状态的标准I/O流;
C、删除所有通过tmpfile函数创建的临时文件;
D、_exit(status);
3、调用_exit/EXIT令进程终止
终止进程前做的事:
A、关闭所有仍处于打开状态的文件描述符
B、将调用进程的所有子进程托付给init进程收养
C、向调用进程的父进程发送SIGCHLD(17)信号
D、令调用进程终止运行,将status的低八位作为退出码保存在其终止状态中
异常终止:
1、当进程执行了某些在系统看起来具有危险性的操作,或系统本身发生了
某种故障或意外,内核会向相关进程发送特定的信号,如果进程无意针对
收到的信号采取补救措施,那么内核将按照缺省方式将进程杀死并视情节
生成和核心转储文件(core)以备事后分析,俗称吐核
SIGILL(4):进程试图执行非法指令
SIGBUS(7):硬件或对齐错误
SIGFPE(8):浮点异常
SIGSEG(11):无效内存访问
SIGPWR(30):系统供电不足
2、人为触发信号
SIGINT(2):Ctrl+C
SIGQUIT(3):Ctrl+\
SIGKILL(9):不能被捕获或忽略的进程终止信号
SIGTERM(15):可以被捕获或忽略的进程终止信号
3、向进程自己发送信号
#include<stdlib.h>
void abort(void);
功能:向调用进程发送SIGABRT(6)信号,该信号默认情况下可使进程
结束,无参数,不返回!