欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

详细流程和相关功能

最编程 2024-07-04 07:23:35
...

进程的基本概念-----------------

进程的基本概念:正在运行的程序

代码 -- 工程师用开发工具所支持的语言写出来的自己能看懂的字符文件;  静态的 -- 磁盘中   main.c

程序 -- 通过编译器蒋代码编程生成得到的,就是计算机能读懂的二进制文件;-- 静态的 -- 磁盘中

进程 -- 程序被加载到内存中,产生进程

同一个程序,多次运行,产生不同的进程;

查看进程-----------------------

ps -ef
ps -aux

进程的特点---------------------

动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的

并发性:任何进程都可以同其他进程一起并发执行;(假并发)

独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;

异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进

进程的资源分配-----------------

进程是系统分配资源的最小单位,系统会给每个进程分配4G的虚拟内存:

堆区:手动开辟,手动释放;

栈区:局部变量

数据段:全局变量,静态变量(static)

代码段:常量区,代码

进程的状态---------------------

执行态,就绪态,等待态

执行态:当前该进程正在占用CPU,CPU划分时间片

就绪态:进程做好了一切准备,等待CPU划分时间片

等待态:等待某事件发生(等待态不能直接转化为执行态,只能转化为就绪态)

进程详细讲解及相关函数_父进程

进程管理-----------------------

先用ps -ef查出要杀死的pid号

kill -9 pid号

进程间关系---------------------

父子关系:该进程是有谁引导产生的,谁就是该进程的父进程,父进程往往拥有子进程的PID

创建进程-----------------------

方式1:运行一个可执行程序

方式2:用函数创建--多进程

获取进程pid--------------------

头文件

#include <sys/types.h>
#include <unistd.h>

pid_t getpid(void);

获取当前进程的进程号

返回值:当前进程的进程号

pid_t getppid(void);

获取当前进程的父进程的进程号

返回值:当前进程的父进程的进程号

结束进程------------------------

return:仅仅在主函数中运行return,可以结束进程;

exit(0);

#include <stdlib.h>

void exit(int status);

功能:结束当前进程

形参:status 一般写0;  exit(0);

返回值:void

特点:退出时,刷新/清理缓冲区;


_exit(0);

#include <unistd.h>

void _exit(int status);

功能:结束当前进程

形参:status 一般写0;  exit(0);

返回值:void

特点:退出时,不刷新/不清理缓冲区;

用函数创建进程-----------------

fork

头文件

#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);

功能:创建进程

形参:void  无

返回值:pid_t  int类型的pid号

失败:返回-1;

成功:在父进程中返回子进程的PID号;

      在子进程中返回0;

fork创建的子进程的特点:

子进程复制父进程的资源(堆区,栈区,数据段,代码段),复制之后两个进程相互独立,互不干扰

运行顺序不确定,有CPU算法调度

子进程的运行是从fork的下一行


特殊进程:

父子进程:父进程有子进程的PID号,父进程可以管理子进程(管理:杀死,暂停,恢复,清理资源);

0号进程:系统启动的引导进程

1号进程:系统启动起来运行的第一个进程

孤儿进程:父进程已经结束,子进程还在运行,子进程会被另外一个进程收养;

僵尸进程:子进程退出,父进程在忙,没有时间帮其收尸,此时子进程就会变成僵尸进程;(僵尸进程:已经释放了几乎所有资源,唯独占用一个PID号,Z)

进程等待函数-------------------

wait

头文件

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *wstatus);

功能:阻塞性函数,等待某一个子进程退出,帮其收尸,之后解除阻塞;

形参:wstatus  -- 进程退出时的状态

int num;

其他函数,可以解析num

不关注进程退出时的状态,传入NULL

返回值:退出的子进程的PID号


waitpid-- 等待指定子进程结束

pid_t waitpid(pid_t pid, int *wstatus,int options);

形参:

pid  --  要等待的具体的子进程的进程号

 -- 一般写-1  (等待任意子进程结束)

wstatus  -- 进程退出时的状态

int num; waitpid(pid,&num,。。);

会有其他函数,可以解析通过解析num,知道进程为啥退出

options --  填写0,表示阻塞等待

填写:WNOHANG,表示不阻塞;子进程退出,为其收尸,不退出,直接就运行下一行代码,不阻塞当前进程

返回值:

options如果填写的是0,表示阻塞等待子进程退出,成功返回等到退出的子进程的PID号,失败返回-1;

options如果填写的是WNOHANG,表示不阻塞,如果刚好等到子进程退出,返回子进程的pid号,如果没等到返回0,函数执行失败返回-1;

waitpid(-1,NULL,0)  == wait(NULL);

exec函数族----------------------

在当前进程中运行另外一个进程,当前进程空间会被取代;

头文件

#include <unistd.h>

函数原型

int execl(const char *pathname, const char arg, .../ (char  *) NULL */);

形参:pathname -- 可执行程序的绝对路径

后面的参数:

第一个arg:可执行程序的名字

第二个arg:给可执行程序传入的参数

......

最后一个必须是NULL;

int execlp(const char *file, const char *arg, .../* (char  *) NULL */);

形参:

file --

如果是系统的指令,不用加路径                

如果是自己写的可执行程序,依旧是绝对路径

后面的参数:

第一个arg:可执行程序的名字

第二个arg:给可执行程序传入的参数

......

最后一个必须是NULL;

int execv(const char *pathname, char *const argv[]);

int execvp(const char *file, char *const argv[]);


举例:

execl(“/bin/ls”,”ls”,”-l”,”-i”,NULL);

char *argv[] = {”ls”,”-l”,”-i”,NULL};

execv(“/bin/ls”,argv);

fork的特点子进程复制父进程资源,和父进程并发运行;

fork+exec函数族:子进程空间被exec传入的进程覆盖,和父进程并发运行

vfork自己的特点:子进程共享父进程资源,子进程先运行,子进程退出之后父进程才能运行

vfork+exec函数族结合:

vfork就会被重新开辟空间,不再和父进程共享资源,同时子进程和父进程并发运行;

相关练习例题-------------------

例题1.

int main()

{

fork();

fork();

fork();

printf(“hello world\n”);

}

分析为什么打印8个hello world,用代码体现

#include <stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
    pid_t pid=fork();
    if(pid>0)
    {
        pid_t pid1=fork();
        if(pid1>0)
        {
            pid_t pid2=fork();
            if(pid2>0)
            {
                printf("son:%d\n",pid);
            }
            else if(pid2==0)
            {
                pid_t ppid1=getppid();
                printf("father:%d\n",ppid1);
            }
        }
        else if(pid1==0)
        {
            pid_t pid3=fork();
            if(pid3>0)
            {
                printf("son:%d\n",pid3);
            }
            else if(pid3==0)
            {
                pid_t ppid2=getppid();
                printf("father:%d\n",ppid2);
            }
        }
    }
    else if(pid==0)
    {
        pid_t pid1=fork();
        if(pid1>0)
        {
            pid_t pid2=fork();
            if(pid2>0)
            {
                printf("son:%d\n",pid2);
            }
            else if(pid2==0)
            {
                pid_t ppid3=getppid();
                printf("father:%d\n",ppid3);
            }
        }
        else if(pid1==0)
        {
            pid_t pid3=fork();
            if(pid3>0)
            {
                printf("son:%d\n",pid3);
            }
            else if(pid3==0)
            {
                pid_t ppid4=getppid();
                printf("father:%d\n",ppid4);
            }
        }
    }
    
    return 0;
}

例题2:父进程监测子进程状态,子进程死亡,父进程立马重新创建子进程;

#include<stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include<time.h>
#include<stdlib.h>
int main()
{
	while(1)
	{
		pid_t pid=fork();
		if(pid>0)//父进程
		{
				int num3=getpid();
				printf("我是父进程:%d\n",num3);
				wait(NULL);//父进程开始给子进程收尸
				sleep(2);//3秒后创建新的子进程
		}
		else if(pid==0)//子进程
		{
			int num=0;
			while(1)
			{
				num++;
				int num2=getpid();
				sleep(1);
				printf("我是子进程:%d\n",num2);//打印5次子进程的pid号后子进程死掉
				if(num==5)
				{
					exit(0);//子进程退出
				}
			}
		}
	}	
	return 0;
}
例题3:实现运行当前进程,并发运行另外一个进程,可以是:ls -l也可以是自己的另外一个进程(fork/vfork + exec函数族)
#include<stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include<stdlib.h>
int main()
{
	pid_t pid=fork();
	if(pid>0)
	{
			printf("hello\n");
	}
	else if(pid==0)
	{
		execlp("ls","ls","-li","-a",NULL);
	}
	return 0;
}
例题4:实现顺序播放mp3音乐  (fork+ exec函数族)
#include<stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include<stdlib.h>
#include<glob.h>
int cur=0;
int main()
{
	pid_t pid=0;
	glob_t song;
	glob("/home/fuc/音乐/*.mp3",0,NULL,&song);
	t:
	pid=fork();
	for(int i=0;i<song.gl_pathc;i++)//打印当强文件内的歌曲
        //g1_pathc是获取当前文件夹内有多少个以.mp3结尾的文件
	{
		printf("%s\n",song.gl_pathv[i]);
	}
	if(pid==0)//子进程进行播放歌曲
	{
		execlp("mpg123","mpg123",song.gl_pathv[cur],NULL);
    //第一个参数:系统文件不需要加路径,第二个参数,功能,第三个参数,播放相应的mpg
        //第四个参数以NULL结尾
	}
	else if(pid>0)
	{
		wait(NULL);//当子进程一首歌播放完
		cur++;//播放下一首歌
		if(cur==song.gl_pathc)
		{
			goto t;
		}
	}
	return 0;
}

推荐阅读