进程基本概念和应用

1.查看进程:
ps axf
ps -ef|book 查看所有为包含book的进程
2.fork后父子进程区别:
拷贝,克隆,一模一样
fork返回值不同 pid不同 ppid不同
未决信号和文件锁不继承,资源利用量清0.
3.fork前需要执行刷新流操作: fflush(null);

进程状态STAT:

R (TASK_RUNNING),可执行状态
只有在该状态的进程才可能在CPU上运行。而同一时刻可能有多个进程处于可执行状态,这些进程的task_struct结构(进程控制块)被放入对应CPU的可执行队列中(一个进程最多只能出现在一个CPU的可执行队列中。
S (TASK_INTERRUPTIBLE),可中断的睡眠状态:
等待信号量,socket,被放入等待队列中。
D (TASK_UNINTERRUPTIBLE),不可中断的睡眠状态:
不响应信号量,无法被kill-9杀死。存在意义:内核的某些处理流程是不能被打断的。
T (TASK_STOPPED or TASK_TRACED),暂停状态或跟踪状态:
向进程发送一个SIGSTOP信号,它就会因响应该信号而进入TASK_STOPPED状态。
向进程发送一个SIGCONT信号,可以让其从TASK_STOPPED状态恢复到TASK_RUNNING状态。
Z (TASK_DEAD - EXIT_ZOMBIE),退出状态,进程成为僵尸进程。
X (TASK_DEAD - EXIT_DEAD),退出状态,进程即将被销毁。

孤儿进程:

父进程结束,而子进程还在运行,其资源由Init进程(PID=1)接管。

僵尸进程:

子进程结束,但是父进程未使用wait函数进行收尸,导致其变为僵尸进程。

vfork():

子进程和父进程共用同样的数据块,且只能执行exec函数簇 或者 exit退出。

fork():

子进程和父进程共用同样的数据块,但是当存在写操作时,其中一个进程会拷贝另一个进程的数据到一个新的数据块中(谁写谁拷贝)。

进程终止

5种正常终止:
1.main执行 return
2.进程调用exit
3.进程调用_exit或_EXIT
4.最后一个线程从其启动例程返回
5.最后一个线程调用pthread_exit
3种异常终止:
1.调用 abort 产生SIGABRT
2.接到一个信号并终止
3.最后一个线程对取消请求做出响应

进程销毁

wait()函数 子进程改变状态 父进程才可以调用该函数
1.wait(*int status)
阻塞等待
当参数不为空时,会将进程状态信息保存到status指针指向的Int地址中
返回值:
成功:返回终止进程的pid号 失败:-1

2.waitpid(pid_t pid,*int status,int option)
非阻塞等待 使用option
参数1:子进程号
pid<-1 销毁进程组识别码为 pid 绝对值的任何子进程。
pid=-1 销毁任意的子进程 相当于wait()
pid==0 销毁进程组识别码与目前进程相同的任何子进程。
pid>0 销毁任何子进程识别码为 pid 的子进程。
参数2:进程状态
参数3:选项
WNOHANG 如果没有子进程退出 立即返回

linux管道命令: |wc  计算字数:
			-c或--bytes或--chars 只显示Bytes数。
-			l或--lines 显示行数。
			-w或--words 只显示字数。
			--help 在线帮助。
			--version 显示版本信息。

1.多进程 筛选质数(交叉分配法)

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
//质数范围
#define Left 30000000
#define Right 30000200
#define N 3//corss assignment 3个进程
//find zhishu
int main()
{
int mark;
for(int n=0;n<N;n++)
{
        pid_t pid=fork();
        if(pid<0)
        {
        perror("fork failure");  
            for(int j=0;j<n;j++) wait(NULL);
        exit(1);
        }
        if(pid==0)
        {
                for(int i=Left+n;i<=Right;i+=N)
                {
                mark=1; 
                for(int j=2;j<i/2;j++)
                  {       
                        if(i%j==0) {
                        mark=0;break;}


                }
                if(mark)
                printf("[%d]%d is a primer\n",n,i);
                }
                exit(0);//子进程退出
        }
}

        for(int n=0;n<N;n++)
          wait(NULL);//回收子进程号

        exit(0);
}
                    
exec函数族

由一个新的进程映像替换当前进程
执行一个文件
int execl(const char* path,const char* arg,…);
参数1:可执行二进制文件路径
参数2:命令
err=execl("/bin/date",“date”,"+%s",NULL);
返回值err:-1失败

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

int main()
{
puts("begin!");
fflush(NULL);
pid_t pid=fork();
if(pid<0){perror("fork");exit(1);};
if(pid==0){
execl("/bin/date","date","+%s",NULL);//进程替换 执行date+%s
perror("execl()"); exit(1);//如果替换不成功执行这句
}
wait(NULL);//父进程销毁子进程
puts("end!");
exit(0);
}

使用exec函数族实现shell外部命令

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<glob.h>
#include <sys/types.h>
#include <sys/wait.h>
#define DELIMS " \t\n" //分隔符

/*typedef struct {
               size_t   gl_pathc;    /* Count of paths matched so far  
               char   **gl_pathv;    /* List of matched pathnames.  
               size_t   gl_offs;     /* Slots to reserve in gl_pathv.  
           } glob_t;
           */
struct cmd_st
{
glob_t globres;//结构体可以多个类型
};
static void prompt(void)
{
printf("myshell-0.1$");
}

static void parse(char *line,struct cmd_st *res)
{
char *tok;
int i=0;
while(1){
        tok=strsep(&line,DELIMS);
        // 将line 中的长串内容 以DELIMS的分隔符的形式 分割为若干子串 返回值为指针
        if(tok==NULL) break;
        if(tok[0]=='\0') continue;
        glob(tok,GLOB_NOCHECK|GLOB_APPEND*i,NULL,&res->globres);
        //动态存储分割得到的子串
        // GLOB_NOCHECK   
        //GLOB_APPEND追加(第一次不追加 以后每次都追加i初始为0  因此初始不追加)
        //&res->globres存储的地址
        i=1;
        }
}//拆分命令串
int main()
{
        char *linebuf=NULL;
        size_t linebuf_size=0;
        struct cmd_st cmd;
        //glob_t globres;
        while(1)
        {
        prompt();
        if(getline(&linebuf,&linebuf_size,stdin)<0) break;
         parse(linebuf,&cmd);//CMD存储命令
        if(0){/*do sth*/}//如果是内部命令 比如cd exit 
        else{
        //外部命令
                pid_t pid=fork();
                if(pid<0){perror("fork failure");
                                exit(1);
                        }
                if(pid==0){
                        execvp(cmd.globres.gl_pathv[0],cmd.globres.gl_pathv);//子进程被新的进程映像替换
                        //环境变量下的exec函数
                        // int execvp(const char *file, char *const argv[]);
                        perror("execvp faliure");exit(1);       }
               else wait(NULL);//父进程
                                
                        }
        }

exit(0);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
进程和线程是操作系统中的两个基本概念,它们都是用来执行程序的执行单元,但在一些方面有着明显的区别。 1. 进程(Process): - 进程程序在执行过程中的一个实例。 - 每个进程都有自己的独立内存空间,包括代码段、数据段和堆栈段。 - 进程之间相互独立,拥有各自的资源,通信需要通过进程间通信(IPC)机制。 - 进程拥有自己的进程控制块(PCB),用于描述进程的状态、资源和调度信息。 2. 线程(Thread): - 线程是进程中的一个执行单元。 - 多个线程可以共享同一个进程的内存空间,包括代码段、数据段和堆栈段。 - 线程之间共享进程的资源,如打开的文件、信号处理等。 - 线程由线程控制块(TCB)来描述,每个线程有自己的栈和寄存器上下文。 区别: 1. 资源占用:每个进程都有独立的内存空间和系统资源,而线程共享进程的资源。 2. 创建销毁开销:创建或销毁进程比线程开销大,因为进程需要分配独立的内存空间和系统资源,而线程只需要创建线程控制块。 3. 切换开销:进程切换的开销较大,需要保存和恢复整个进程的上下文,而线程切换只需要保存和恢复线程的上下文。 4. 通信和同步:进程间通信需要使用进程间通信机制,如管道、消息队列等。线程间通信和同步相对容易,可以使用共享内存、信号量、互斥量等机制。 总结: 进程和线程都是用于执行程序的执行单元,但进程是资源分配的基本单位,线程是CPU调度的基本单位。多线程比多进程更轻量级,线程之间的切换开销更小,但进程之间相互独立,安全性更高。在实际应用中,需要根据具体需求选择使用进程还是线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值