嵌入式开发Day10-12(2024.03.26-28)

本文详细介绍了进程的概念、并发与并行的区别,Linux下的进程管理方法如getpid、进程状态和常用命令,包括fork函数实现父子进程、exit和wait函数的应用,以及进程替换的exec函数族,最后展示了通过execl执行ls-l的例子。
摘要由CSDN通过智能技术生成

进程

概念

进程是程序执行的过程,进程是系统分配资源的最小单位,由操作系统统一调度。
程序是静态的,进程是动态的,包括创建、调度、消亡。

并发与并行

并发:宏观并行,微观串行(CPU轮流使用)
并行:宏观和微观都是并行(CPU独立占用)

Linux进程管理

采用树形结构,为每个进程分配一个ID,ID作为当前进程的唯一标识,进程结束则收回。
进程ID和父进程ID分别通过getpid() 和 getppid() 函数来获取

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

       pid_t getpid(void);
       pid_t getppid(void);

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
 //pid_t getpid(void);
 //pid_t getppid(void);

int main(){

        pid_t pid = getpid();
        pid_t ppid = getppid();
        printf("the programmer id is : %d\n",pid);
        printf("the programmer father id is : %d\n",ppid);
        return 0;
}

进程地址空间

进程的状态

进程相关命令

ps

显示当前进程
菜鸟教程

top

菜鸟教程

pstree

kill

创建进程

fork函数

fork函数会创建一个新的进程,调用fork函数的进程为父进程,产生的新进程为子进程

#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);

返回值:返回给父进程的是子进程pid,返回给子进程0,失败返回-1,并设置errno
子进程执行的代码和父进程调用fork之后的代码一致,父进程先执行fork后的代码,子进程后执行一遍。
父子进程的执行顺序由操作系统的调度算法决定。
子进程会拷贝父进程的地址空间的数据(copy or write)。

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

//       pid_t fork(void);


int main(){
        pid_t cpid;
        printf("fork 之前:\n");
        cpid = fork();
        if(cpid == -1){
                perror("[ERROR] fork():");
        }
        printf("fork  之后\n");
        printf("get pid: %d \n",getpid());
        printf("Hello World .\n");
        return 0;
}

结果

fork 之前:
fork  之后
get pid: 35548 
fork  之后
Hello World .
get pid: 35549 
Hello World .

父子进程执行不同任务

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


int main(void){
        pid_t cpid;
        cpid = fork();
        if(cpid == -1){
                perror("[ERROR] fork : \n");
        }
        else if(cpid == 0){
                printf("Child process task. \n");//子进程中执行
        }
        else if(cpid > 0){
                printf("Parent process task.\n");//父进程中执
        }
        printf("Parent and Child process task.\n");// 父子进程一起执行

        return 0;
}

结果

root@wangjudealy:/learn# ./a.out 
Parent process task.
Parent and Child process task.
Child process task. 
Parent and Child process task.

最好由父进程统一创建管理子进程

创建多个子进程

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



int main(void){
        pid_t cpid;
        cpid = fork();
        if(cpid == -1){
                perror("[ERROR] fork : \n");
                exit(EXIT_SUCCESS);
        }
        else if(cpid == 0){
                printf("Child A process task. pid is < %d > \n",getpid());//子进程A
                printf("Parent process is < %d >\n",getppid());
                printf("=====================================");
                sleep(2);
                exit(EXIT_SUCCESS);
        }
        else if(cpid > 0){
                cpid = fork();
                if(cpid == -1){
                        perror("[ERROR] fork : \n");
                        exit(EXIT_SUCCESS);
                }
                else if(cpid == 0){
                        printf("Child B process task. pid is < %d > \n",getpid());//子进程B
                        printf("Parent process is < %d >\n",getppid());
                printf("=====================================");

                        sleep(2);
                        exit(EXIT_SUCCESS);
                }
                else if(cpid > 0){
                cpid = fork();
                if(cpid == -1){
                        perror("[ERROR] fork : \n");
                        exit(EXIT_SUCCESS);
                }
                else if(cpid == 0){
                        printf("Child C process task. pid is < %d > \n",getpid());//子进程C
                        printf("Parent process is < %d >\n",getppid());
                        printf("=====================================");

                        sleep(2);
                        exit(EXIT_SUCCESS);
                }
        }


        }

        printf("Parent and Child process task.\n");// 父子进程一起执行

        return 0;
}

结果

root@wangjudealy:/learn# ./a.out 
Child A process task. pid is < 35749 > 
A Parent process is < 35748 >
=====================================
Parent and Child process task.
Child C process task. pid is < 35751 > 
root@wangjudealy:/learn
Child B process task. pid is < 35750 > 
B Parent process is < 1 >
=====================================
C  Parent process is < 1 >
=====================================

进程的退出

进程退出时操作系统回收进程地址空间,并清理相关的数据结构

exit函数

终止进程,并刷新缓冲区

#include <stdlib.h>
void exit(int status);

_exit函数

exit底层调用 _exit,_exit终止进程不刷新缓冲区。

#include <unistd.h>
void _exit(int status);

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

//       void exit(int status);

//       pid_t fork(void);


int main(void){

	pid_t cpid;
	cpid = fork();
	
	//创建子进程
	if(cpid == -1){
		printf("进程创建失败!!!\n");
		exit(EXIT_FAILURE);
	}
	else if(cpid == 0){
		printf("子进程 A 创建成功  进程号 < %d > ",getpid());
		exit(EXIT_SUCCESS);
	}	
	else if(cpid > 0){
		cpid = fork();
		if(cpid == -1){
			printf("创建进程 B 失败\n");
			_exit(EXIT_FAILURE);
		}
		else if(cpid == 0){
			printf("子进程 B 创建成功 进程号 < %d >",getpid());
			_exit(EXIT_SUCCESS);
		}
	
	}
	return 0;
}

结果,只有A进程中的语句被打印,(printf是带有缓冲区的,exit退出时刷新缓冲区)

root@wangjudealy:/learn# 子进程 A 创建成功  进程号 < 36858 > 

进程的等待

子进程运行结束后,进去僵死状态,并释放资源子进程在内核中的数据结构依然保留
父进程调用wait() ,与 waitpid() 函数等待子进程退出后,释放子进程遗留的资源

wait与waitpid

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
wstatus 该指针保存子进程退出状态值,获取具体值要使用 WEXITSTATUS() 宏定义
成功返回子进程pid,失败返回-1
wait调用后会阻塞调用进程,收回僵死状态的子进程的资源后返回。
pid_t waitpid(pid_t pid, int *wstatus, int options); pid = -1 :等待任意进程退出 pid > 0 : 等待特定进程退出 option:是否阻塞

进程替换

创建进程后,pid以及在内核中的信息保持不变,但所执行的代码进行替换
作用:通过一个进程启动另一个进程
应用:程序启动器,在一个程序里调用另一个应用的功能

exec函数族

#include <unistd.h>
extern char **environ;
int execl(const char *pathname, const char arg, …
/
(char *) NULL */);
int execlp(const char *file, const char arg, …
/
(char *) NULL */);
int execle(const char *pathname, const char arg, …
/
, (char *) NULL, char *const envp[ ] */);
int execv(const char *pathname, char *const argv[ ]);
int execvp(const char *file, char *const argv[ ]);
int execvpe(const char *file, char *const argv[ ],
char *const envp[ ]);

通过execl函数执行 ls -l

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

extern char **environ;

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


int main(void){
	int ret;
	ret = execl("/bin/ls","ls","-l",NULL); //调用ls -l
	if(ret == -1){
		
		perror("[ERROR] excel():");
		exit(EXIT_FAILURE);
	}
	return 0;
}

root@wangjudealy:/learn# ./a.out 
total 100
-rw-r--r-- 1 root root   229 Mar 10 20:54 0310.c
-rw-r--r-- 1 root root   365 Mar 13 23:04 0313.c
-rw-r--r-- 1 root root   334 Mar 14 23:33 0314.c
-rw-r--r-- 1 root root   568 Mar 17 17:31 0317.c
-rw-r--r-- 1 root root   189 Mar 19 22:56 0319.c
-rw-r--r-- 1 root root   282 Mar 27 00:01 0326.c
-rw-r--r-- 1 root root  1252 Mar 28 10:22 032801.c
-rw-r--r-- 1 root root   658 Mar 28 21:03 032802.c
-rw-r--r-- 1 root root   379 Mar 28 21:48 032803.c
-rw-r--r-- 1 root root   314 Mar 28 09:48 0328.c
-rwxr-xr-x 1 root root 16784 Mar 28 21:48 a.out
drwxr-xr-x 2 root root  4096 Mar 17 22:18 day05
drwxr-xr-x 2 root root  4096 Mar 24 23:29 day08
-rw-r--r-- 1 root root   159 Mar  9 11:59 p1.c
-rw-r--r-- 1 root root  1912 Mar  9 19:36 p1.o
-rwxr-xr-x 1 root root 16696 Mar  9 11:31 p1.os
-rw-r--r-- 1 root root   162 Mar 14 23:32 test.c

  • 19
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值