Linux 进程

linux 进程与线程

什么是进程

进程就是程序的一次动态执行的过程

进程是程序执行和资源管理的最小单位(在未被开启线程的情况下)

程序一旦被运行,就会产生一个进程,并且会被每一个进程分配一个0-4G(32OS下)的内存空间,意味着分配空间大小和操作系统的位数有关。

什么是进程标识符

每一个进程都有一个非负整数表示的唯一ID,叫做pid,类似身份证

进程的特点

  • 独立性
    进程是系统中独立存在的实体,它可以拥有自己独立的资源,每个进程都拥有自己私有的地址空间,在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间
  • 动态性
    进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合,程序加入了时间的概念以后,称为进程,具有自己的生命周期和各种不同的状态,这些概念都是程序所不具备的
  • 并发性
    多个进程可以在单个处理器CPU上并发执行,多个进程之间不会互相影响

父子进程

进程A创建了进程B,那么A叫做父进程,B叫做子进程,父进程是相对的概念,理解为人类中的父子关系
pid_t fork(void)
函数功能:使用fork函数创建一个进程
函数返回值:fork函数调用成功,返回两次 返回值为0 ,代表当前进程是子进程
返回值非负数,代表当前进程为父进程 调用失败 ,返回-1

fork创建子进程的一般目的

一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的——父进程等待客户端的服务请求。当这种情求达到时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达。

一个进程要执行一个不同的程序。这对shell是常见的情况,在这种情况下子进程从fork返回后立即调用exec。

模拟socket 创建进程(服务器对接客户端的应用场景)示例代码:

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

int main()
{
   pid_t  pid;
   int data;

   while(1){
        printf("please input a data\n");
        scanf("%d",&data);

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

            if(pid >0){

            }
            else if(pid == 0){
                  while(1){
                        printf("do net request,pid=%d\n",getpid());
                        sleep(3);
                  }
            }
        }
        else{
           printf("wait, do noting\n");
        }
   }
   return 0;
}

输入非1时候,模拟没有客户端进行交互
输入1时候,模拟有客户端进行交互 ,创建子进程来进行交互,子进程号为:1111
模拟多个客户端进行交互时 ,创建多个子进程来进行交互,子进程号为:9756 / 9758 / 9759

vfork创建进程

vfork直接使用父进程存储空间,不用拷贝(写操作才进行拷贝)
vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行

ps 常带的一些参数

命令参数说明
-e显示所有进程.
-f全格式
-h不显示标题
-l长格式
-w宽输出
-a显示终端上的所有进程,包括其他用户的进程
-r只显示正在运行的进程
-u以用户为主的格式来显示程序状况
-x显示所有程序,不以终端机来区分
ps -ef 的每列的含义是什么呢

在这里插入图片描述

子进程退出方式

正常退出:

  1. Mian函数调用return
  2. 进程调用exit(),标准c库
  3. 进程调用_exit()或者——Exit(),属于系统调用
  4. 进程最后一个线程返回
  5. 最后一个线程调用pthread_exit
#include<stdlib.h>
void exit(int status);


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


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

异常退出:

  1. 调用abort
  2. 当进程收到某些信号时候,如ctrl+C
  3. 最后一个线程对取消(cancellation),请求作出响应
等待子进程退出

为什么要等待子进程退出?

创建子进程的目的就是为了让它去干活,在网络请求当中来了一个新客户端介入,创建子进程去交互,干活也要知道它干完没有.

僵尸进程

子进程退出状态不被收集,会变成僵死进程(僵尸进程)

等待函数:wait(状态码) 的使用

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

pid_t wait(int *status);    //参数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位置阻塞,等子进程退出后,父进程开始运行。

  • 如果一个子进程已终止,正等待父进程获取其终止状态,则会取得该子进程的终止状态立即返回。

  • 如果它没有任何子进程,则立即出错返回。

收集退出进程状态
pid = vfork();

    if(pid >0){
       while(1){
               printf("cnt=%d\n",cnt);
               printf("this is father print pid is %d\n",getpid());
               sleep(1);
       }
    }else if(pid == 0){
         wait(NULL);    // 参数:status  是一个地址  为空 表示不关心退出状态
         while(1){
               printf("this is child print pid is =%d\n",getpid());
               sleep(1);
               cnt++;
               if(cnt == 3 ){
                  exit(0);
               }
         }
    }
等待函数:waitpid()的使用
wait和waitpid的区别之一

wait使父进程(调用者)阻塞,waitpid有一个选项 ,可以使父进程(调用者)不阻塞。
pid_t waitpid(pid_t pid , int *status ,int options);

pid == -1等待任一子进程。就这一方面而言,waitpid与wait等效。
pid > 0等待其进程ID与pid相等的子进程。
pid == 0等待其组ID等于调用进程组ID的任一子进程
pid <-1等待其组ID等于pid绝对值的任一子进程。
WCONTINUED若实现支持作业控制,那么由pid指定的任一子进程在暂停后已经继续,但其状态尚未报告,则返回其状态(POSIX.1的XSI扩展)
WNOHANG若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时其返回值为0;
WUNTRACED若某实现支持作业控制,而由pid指定的任一子进程已处于暂停状态。

孤儿进程

父进程如果不等待子进程退出,在子进程结束前就了结束了自己的“生命”,此时子进程就叫做孤儿进程。

孤儿进程被收留

Linux避免系统存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程【init进程(pid=1)是系统初始化进程】。init 进程会自动清理所有它继承的僵尸进程。

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

int main()
{
    pid_t pid;
    int cnt=0;
    int status =10;
    pid = fork();

    if(pid >0){
               printf("this is father print pid is %d\n",getpid());
       }
    else if(pid == 0){
         while(1){
               printf("this is child print pid is =%d,my father pid is=%d\n",getpid(),getppid());
               sleep(1);
               cnt++;
               if(cnt == 3 ){
                  exit(5);
               }
         }
    }
   return 0;
}

exec族函数

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

exec族函数作用

  1. 一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的——父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达。
  2. 一个进程要执行一个不同的程序。这对shell是常见的情况。在这种情况下,子进程从fork返回后立即调用exec。

system函数

 #include<stdlib.h>
int system(const char * string);

system和execl不同的是:sysem运行完调用的可执行文件后还会继续执行源代码。

创建守护进程

1.创建子进程,父进程退出
2.在子进程中创建新会话
3.改变当前目录为根目录
4.重设文件权限掩码
5.关闭文件描述符

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{

	//功能:实现守护进程的创建
	//(1)创建子进程并让父进程退出
	pid_t pid = fork();
	if(pid < 0)
	{
		perror("fork error");
		exit(-1);
	}
	else if(pid > 0)
	{
		//让父进程退出
		exit(0);
	}

	//(2)创建新的会话组
	setsid();

	//(3)改变守护进程工作目录为根目录
	chdir("/");

	//(4)设置文件掩码
	umask(0);
	//(5)关闭从父进程拷贝过来的文件描述符
	int fdtablesize = getdtablesize();
	int i;
	for(i=0;i<fdtablesize;i++)
	{
		close(i);
	}

	//剩下的都是子进程
	//创建并打开一个文件
	char buf[30] = {"I am Daemon Process!\n"};
	while(1)
	{
		int fw = open("Message.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);
		if(fw < 0)
		{
			perror("open error");
			exit(-1);
		}
		//写入文件
		write(fw, buf, strlen(buf));
		close(fw);
		sleep(1);
	}

	return 0;
}

popen函数

#include<stdio.h>
FILE *popen (const char *command ,const char *type); 
int pclose(FILE *stream); 

函数参数:
command: 是一个指向以NULL结束的shell命令字符串的指针。这行命令将被传到bin/sh并且使用 -c标志,shell将执行这个命令。
type: 只能是读或者写中的一种,得到的返回值(标准I/O流)也具有和type相应 的只读或只写类型。如果type是”r“则文件指针连接到command的标准输出;如果type是”w“则文件指针连接到command的标准输入。

返回值: 如果调用成功,则返回一个读或者打开文件的指针,如果失败,返回NULL,具体错误要根据errno判断

函数作用: popen()函数用于创建一个管道:其内部实现为调用fork产生一个子进程,执行一个shell以运行命令来开启一个进程这个进程必须由pclose函数关闭。

popen函数的使用

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

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

   fp = popen("ps","r");
   int nread = fread(ret,1,1024,fp);

   printf("read ret %d byte ,ret =%s\n",nread ,ret);
   return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值