1.main 函数由谁调用
2.程序如何结束
-(1)正常终止:return、exit、_exit。
-(2)非正常终止:自己或他人发送非正常终止信号终止进程。
3.atexit 注册进程终止处理函数
#include
#include
#include
void func1(void)
{
printf("func1\n");
}
void func2(void)
{
printf("func2\n");
}
int main(void)
{
printf("hello world.\n");
//当进程被正常终止时,系统会自动调用这里注册的func1执行
atexit(func2);//注册进程终止处理函数2
atexit(func1);//注册进程终止处理函数1
printf("my name is rgd.\n");
//return 0;
//exit(0);
_exit(0);
}
1、环境变量
#include
int main(void)
{
extern char** environ;//声明即可使用,但是此变量是在外部定义的
int i=0;
while(NULL!=environ[i]){
printf("s%\n",environ[i]);i++
}
return 0;
}
2、进程运行的虚拟地址空间
1、什么是进程
2、进程 ID
#include
#include
#include
int main(void)
{
pid_t p1=-1,p2=-1;
printf("helloworld!\n");
p1=getpid();printf("pid = %d.\n", p1);
p2 = getppid();printf("parent id = %d.\n", p2);
return 0;
}
3、多进程调度原理
1、为什么要创建子进程
2、fork系统调用的内部原理
#include
#include
#include
int main(void)
{
pid_t p1=-1;
p1=fork();//返回两次
if(p1==0){//是子进程
sleep(1);//先sleep一下让父进程先运行,先死
printf("子进程, pid = %d.\n", getpid());
printf("子进程, 父进程 ID = %d.\n", getppid());
}
else if(p1>0){//是父进程
printf("父进程, pid = %d.\n", getpid());
printf("父进程, p1 = %d.\n", p1);
}
else ;// 这里一定是 fork 出错了
//=======在这里的操作会被执行两遍
//printf("hello world,pid=%d.\n",getpid());
return 0;
}
3、关于子进程
1、子进程继承父进程中打开的文件(同一个fd)
2、父子进程各自打开文件实现文件共享(不同fd)
3、conclusion
#include
#include
#include
#include
#include
#include
int main(void)
{
int fd=-1;
pid_t pid=-1;
//============fork个子进程
pid=fork();
if(pid>0){//parent
printf("parent.\n");
fd=open("1.txt",O_RDWR|O_APPEND);
if(fd<0){
perror("open");return -1;
}
write(fd,"hello",5);
sleep(1);
}
else if(pid==0){//child
printf("child.\n");
fd=open("1.txt",O_RDWR|O_APPEND);
if(fd<0){
perror("open");return -1;
}
write(fd,"world",5);
sleep(1);
}
else{
perror("fork");exit(-1);
}
close(fd);
}
#include
#include
#include
#include
#include
#include
int main()
{
int fd=-1;
pid_t pid=-1;
fd = open("1.txt", O_RDWR | O_TRUNC);//父子进程同一个fd,默认续写
if(fd<0){
perror("open");return -1;
}
pid=fork();
if(pid>0){//父亲
printf("parent.\n");
write(fd, "hello", 5);sleep(1);
}
else if(pid==0){//儿子
printf("child.\n");
write(fd, "world", 5);sleep(1);
}
else{//失败
perror("fork");exit(-1);
}
close(fd);return 0;
}
1、进程的诞生
2.进程的消亡
3、僵尸进程
4、孤儿进程
1.wait 工作原理
2、wait 实战编程
#include
#include
#include
#include
#include
int main(void)
{
pid_t pid=-1;
pid_t ret=-1;
int status=-1;
pid=fork();
if(pid>0){//parent====对僵尸子进程解放其栈与struct结构体资源
printf("parent.\n");
ret=wait(&status);//status表示子进程返回子进程终止的状态,ret即为回收对象子进程的pid号
printf("子进程已经回收,子进程pid=%d.\n",ret);
printf("子进程是否正常退出:%d\n",WIFEXITED(status));
printf("子进程是否非正常退出:%d\n"WIFSIGNALED(status));
pritnf("正常终止的终止值是:%d.\n",WEXITSTATUS(status));
}
else if(pid==0){//child
printf("child pid = %d.\n",getpid());
return 51;//异常退出
//exit(0);//正常退出
}
else return -1;
return 0;
}
1.wait 和 waitpid 差别
2.waitpid 原型介绍
3、代码示例
4、竞态初步引入
1、为什么需要 exec 族函数
2、exec 族的 6 个函数介绍
/*execl和execv:这两个是最基本的exec,都可以用来加载运行可执行程序,
*区别是传参格式不同。
*execl是多个参数排列的形式。
*execv多多参数事先放在一个字符串数组NULL结尾,再把这数组作为形参传入*/
int execl(const char* path,const char* arg,/*...,(char*)NULL*/);
int execv(const char* path,const char* argv[]);
/*execlp和execvp:这两个函数较上面来说,上面两个函数必须指定可执行程序的全路径,而这两个加了p的函数可以只指定file即文件名,函数会到环境变量PATH所指定的目录下去找。
*/
int execlp(const char* file,const char* arg,/*...,(char*)NULL*/);
int execvp(const char* path,char* const argv[]);
/*这两个函数的形参列表多了个字符串数组envp,即环境变量*/
int execle(const char* file,const char* arg,/*...,(char*)NULL,char* const envp[]*/);
int execvpe(const char* file,char* const argv[],char* const envp[]);
3、exec实战1
execl("/bin/ls","ls","-l","-a",NULL);
char* const arg[]={"ls","-l","-a",NULL};
execv("/bin/ls",arg);
execl("hello","aaa","bbb",NULL);
char * const arg[] = {"aaa", "bbb", NULL};
execv("hello",arg);
4、exec 实战 2
execlp("ls ","ls","-l","-a",NULL);
char* const envp[]={"AA=aaaa","XX=abcd",NULL};
execle("hello","hello","-l","-a",NULL,envp);
5、execle和execvpe
1、进程的 5 种状态
2、进程各种状态之间转换图
3、system 函数简介
system("ls -al /etc/passwd/etc/shadow");
1.无关系
2.父子关系
3.进程组(group):由若干进程构成一个进程组,组内共享一些文件。
4.会话(session):会话就是进程组的组。
1、进程查看命令 ps
2、向进程发送信号指令:kill
3.守护进程
4、常见守护进程
1.任何一个进程都可以将自己变成守护进程
2.create_deamon()函数要素(调用该函数即可成为守护进程):
#include
#include
#include
#include
#include
void create_daemon(void);
int main(void)
{
create_daemon();
while(1){
printf("i am running.\n");sleep(1);
}
return 0;
}
// 函数作用就是把调用该函数的进程变成一个守护进程
void create_daemon(void)
{
pid_t pid=0;
pid=fork();
if(pid<0){
perror("fork");exit(-1);
}
else if(pid>0){//parent process
exit(0);
}
//===此处就是孤儿进程
//设置新的会话session,脱离控制台
pid=setsid();
if(pid<0){
perror("setsid");exit(-1);
}
//将当前进程的目录设置为根目录
chdir("/");
//umask设置为0确保之后进程有最大的文件操作权限
umask(0);
//关闭all fd,前提要知道当前文件系统所允许打开最大文件描述符数目
int cnt=sysconf(_SC_OPEN_MAX);int i=0;
for(i=0;i<cnt;i++)
close(fd);
//将文件描述符0、1、2定位到“/dev/null”
open("/dev/null",O_RDWR);
open("/dev/null",O_RDWR);
open("/dev/null",O_RDWR);
}
1、三个函数:
void openlog(const char* ident,int option,int facility);
void syslog(int priority,const char* format,...);
void closelog(void);
2、syslog工作原理
#include
#include
#include
int main(void)
{
printf("my pid=%d.\n",getpid());
openlog(LOG_INFO,"this is my log info.%d",23);
syslog(LOG_INFO,"this is another log info.");
syslog(LOG_INFO,"this is 3th log info.");
closelog();
return 0;
}
1.问题
2.解决方法
#include
#include
#include
#include
#include
#include
#define FILE "/var/aston_test"
void delete_file(void);
int main(void)
{
//首先就是要判断文件是否存在
int fd=-1;
fd=open(FILE,O_RDWR|O_TRUNC|O_CREAT|O_EXCL,0664);
if(fd<0){
if(errno==EEXIST){
printf("进程已经存在,不需要重复执行.\n");return -1;
}
}
atexit(delete_file);//注册进程处理函数
int i=0;
for(i=0;i<10;i++){
printf("i am running...%d\n",i);sleep(1);
}
return 0;
}
void delete_file(void)
{
remove(FILE);
}
1.为什么需要进程间通信
2.什么样的程序设计需要进程间通信。
3.Linux 内核提供的多种进程间通信方式
1、管道(无名管道)
2、有名管道(fifo)
1、基本特点
2、信号量
3、消息队列
4.共享内存
剩余的 2 类 IPC