Linux进程学习笔记

一、创建进程fork的使用

pid_t fork(void);

会返回两次,给父进程和子进程

返回值是0,表示为当前自己的进程

返回值是非负整数,表示为父进程

返回-1,出错

 fork函数调用后,父进程会复制两份fork之下的代码,一份给自己,一份给子进程,并把子进程的fork返回值置1

  • 旧Linux下的拷贝是全拷贝,但是数据若是被子进程修改的话,父进程不会受到干扰
  • 新Linux下的拷贝是copy on write,例如定义的变量值,若是在过程中不会被修改,则不需要拷贝,以共享方式使用,若是需要修改值,则拷贝到各自进程中处理
//fork创建新子进程实例

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

int main()
{
	pid_t pid;
	int data;
	
	while(1){
		printf("please input data:\n");
		scanf("%d",&data);

		if(data == 1){
			pid = fork();

			if(pid > 0){

			}
			else if(pid == 0){

				while(1){

					printf("ask net connect,pid=%d\n",getpid());
					sleep(3);
				}
			}
		}else{
			printf("do nothing!\n");	
		}
	}
	

	return 0;
}

二:vfork

与fork区别

  • 直接使用父进程存储空间,不共享也不复制,这样会改变数值
  • vfork保证子进程先运行,等到子进程exit退出后,父进程才执行

三:进程退出

  1. 正常退出
  • main函数调用return
  • 进程调用exit(),标准c库
  • 进程调用_exit()或_Exit(),属于系统调用
  • 进程最后一个线程调用pthread_exit返回

        2.异常退出

  • 调用abort函数
  • 当进程收到某些信号时,如CTRL+C
  • 最后一个线程对取消请求做出响应

无论是哪种退出,内核都会执行相应代码,这段代码为相应进程关闭所有打开标识符,释放存储器

四:父进程等待子进程退出

1.父进程等待子进程退出,并收集子进程的退出情况 

  • pid_t wait(int *status)
  • status:是一个整数型指针
  • 非空:子进程退出状态放在它指向的地址中,空:不关心退出状态

2.子进程退出状态不被收集,变成僵尸进程(父进程不关心子进程的状态,对于子进程进行的exit不做wait反应)

//僵尸进程
if(pid > 0){
		while(1){
			printf("cnt=%d\n",cnt);
			printf("this is father print:%d\n",getpid());
			sleep(1);
		}
	}
	else if(pid == 0){
		while(1){
			printf("this is child print:%d\n",getpid());
			sleep(1);
			cnt++;
			if(cnt == 3){
				exit(0);
			}
		}
	}
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
	pid_t pid;
	int cnt = 0;
	int status = 10;

	pid = fork();

	if(pid > 0){
		while(1){
			wait(&status); //指针型数据
			printf("status:%d",WEXITSTATUS(status)); //宏定义值,可以返回exit的状态量
			printf("cnt=%d\n",cnt);
			printf("this is father print:%d\n",getpid());
			sleep(1);
		}
	}
	else if(pid == 0){
		while(1){
			printf("this is child print:%d\n",getpid());
			sleep(1);
			cnt++;
			if(cnt == 3){
				exit(3);
			}
		}
	}

	return 0;
}

等待函数

  • pid_t wait(int *status);
  • pid_t waitpid(pid_t pid,int *status,int options);
  • int waitid(idtype_t idtype,id_t id,siginfo_t *infop,int options);
  • 如果其所有子进程都在运行,则阻塞
  • 如果一个子进程状态已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态就立即返回
  • 如果它没有任何子进程,则立即出错返回
  • 区别:wait中会使调用者阻塞,但是waitpid有一个选项可以使调用者不阻塞(options:WNOHANG)

孤儿进程:

  • 父进程如果不等待子进程退出,在子进程运行结束之前就结束了自己的“生命”,则子进程叫做孤儿进程
  • Linux中的init进程(pid = 1)来收集孤儿进程 

五:exec族函数

exec族函数函数的作用:

我们用fork函数创建新进程后,经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序。因为调用exec函数并不创建新进程,所以前后进程的ID并没有改变。

功能:
  在调用进程内部执行一个可执行文件。可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。
函数族:
  exec函数族分别是:execl, execlp, execle, execv, execvp, execvpe

返回值:
  exec函数族的函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。
参数说明:
path:可执行文件的路径名字
arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束
file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。

exec族函数参数极难记忆和分辨,函数名中的字符会给我们一些帮助:
l : 使用参数列表
p:使用文件名,并从PATH环境进行寻找可执行文件
v:应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。
e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量

#include <unistd.h>
extern char **environ;

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);

带e的不要求 

 若是当中出错,可以调用perror("why");来查看原因

 excel:

可以用此函数来查看系统时间

//echoarg.c
#include <stdio.h>

int main(int argc,char *argv[])
{
    int i = 0;
    for(i = 0; i < argc; i++)
    {
        printf("argv[%d]: %s\n",i,argv[i]); 
    }
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);

int main(void)
{
    printf("the current time is\n");
    if(execl("/bin/date","echoarg",NULL,NULL) == -1)
    {
        printf("execl failed!\n");      
	//perror("why"); 
    }
    printf("after execl\n");
    return 0;
}

 

 excelp:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);

int main(void)
{
    printf("the current time is\n");
    if(execlp("date","echoarg",NULL,NULL) == -1)
    {
        printf("execl failed!\n");      
	//perror("why"); 
    }
    printf("after execl\n");
    return 0;
}

 excelp();可以不用添加路径,就能通过环境变量查到可执行文件

execvp:

将excel后面的三个参数另外做成一个数组展示

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);

int main(void)
{
    printf("the current time is\n");

   char *argv[] = {"echoarg",NULL,NULL}; 
   if(execvp("date",argv) == -1)
    {
        printf("execl failed!\n");      
	//perror("why"); 
    }
    printf("after execl\n");
    return 0;
}

 execv:

与前面execl类似,不加p就需要声明绝对路径

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);

int main(void)
{
    printf("the current time is\n");

   char *argv[] = {"echoarg",NULL,NULL}; 
   if(execv("/bin/date",argv) == -1)
    {
        printf("execl failed!\n");      
	//perror("why"); 
    }
    printf("after execl\n");
    return 0;
}

 六:exec函数与fork配合使用

在之前的demo中生成一个可执行文件,之后使用execl调用

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

int main()
{
	pid_t pid;
	int data;
	
	while(1){
		printf("please input data:\n");
		scanf("%d",&data);
		
		if(data == 1){
			
			pid = fork();

			if(pid > 0){
				wait(NULL);
			}
			if(pid == 0){
				execl("./changeData","changeData","test.txt",NULL);
			}
		}else{
			printf("do nothing!\n");	
		}
	}
	

	return 0;
}

七:system函数

int system(const char *cmd);

成功,则返回进程的状态值,当sh不能执行时,返回127;失败返回-1

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

int main()
{
	pid_t pid;
	int data;
	
	while(1){
		printf("please input data:\n");
		scanf("%d",&data);
		
		if(data == 1){
			
			pid = fork();

			if(pid > 0){
				wait(NULL);
			}
			if(pid == 0){
	//			execl("./changeData","changeData","test.txt",NULL);
				system("./changeData test.txt");
			}
		}else{
			printf("do nothing!\n");	
		}
	}
	

	return 0;
}
//日期显示
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);

int main(void)
{
    printf("the current time is\n");
    if(system("date") == -1)
    {
        printf("execl failed!\n");      
	//perror("why"); 
    }
    printf("after execl\n");
    return 0;
}

八:popen();

popen(command,mode);

cmd:使用的命令

mode:“r” / “w”

比system好用的是可以获得输出结果

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

int main(void)
{
	char ret[1024] = {0};
	FILE *fp;

	fp = popen("date","r");
	int n_read = fread(ret,1,1024,fp);

	printf("ret print %d byte,ret=%s",n_read,ret);

	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值