Linux下的进程的有关知识点

????操作系统是个软件系统,协调计算机硬件进行工作,为上层应用提供支持和用户操作。对编程开发来说,它提供API编程接口(文件操作,socket网络编程等)在计算机中,操作系统的定位是一个管理者,对上管理在系统中运行的进程,对下通过驱动程序管理各种硬件。1、与硬件交互,管理所有的软件和硬件资源2、为应用程序提供一个执行环境常用的操作系统:终端的应用:windows、IOS、Android等服...
摘要由CSDN通过智能技术生成

?操作系统
是个软件系统,协调计算机硬件进行工作,为上层应用提供支持和用户操作。对编程开发来说,它提供API编程接口(文件操作,socket网络编程等)在计算机中,操作系统的定位是一个管理者,对上管理在系统中运行的进程,对下通过驱动程序管理各种硬件。
1、与硬件交互,管理所有的软件和硬件资源
2、为应用程序提供一个执行环境
常用的操作系统:
终端的应用:windows、IOS、Android等
服务器应用:windows server、linux(重点)、unix等
?Linux内核
内核是操作系统的核心,具有很多最基本功能,它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性 。Linux 内核由如下几部分组成:内存管理、进程管理、设备驱动程序、文件系统和网络管理等
?虚拟内存
虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。目前,大多数操作系统都使用了虚拟内存,如Windows家族的“虚拟内存”;Linux的“交换空间”等。

进程

运行的程序就称为进程 ,进程是操作系统分配资源和调度的基本单元 ,其实可以理解为程序的运行实例
?进程的特征:
动态性:有生命周期
并发性:同时可以有多个程序,在内存中执行。常常代表的是同时启动多个程序,注意和并行的区别,并行强调的是多个进程同一时间在执行。
独立性:进程有自己的地址空间,运行时在这个地址空间中运行代码,各个进程之间互不影响。
异步性:指的是独立运行,以不可预知的速度推进
?进程的组成:
Linux系统中进程由以下三部分组成: ①进程控制块PCB;②数据段;③正文段
PID:进程ID号
PCB:进程控制块,
linux下叫具体为task_struct 进程的地址空间(虚拟地址空间:地址连续) 代码段、数据段、堆、栈等等(栈地址增长方向:从高到低。堆地址增长方向:从低到高)
假设32系统,共4G的空间
1G:Linux系统内核使用,3G:用户可以使用。
其中0-3G是用户空间,
3G-4G是内核空间 较低3G字节0x00000000 ~ 0xBFFFFFFF称为“用户空间” 最高的1G字节0xC0000000 ~ 0xFFFFFFFF称为“内核空间”
?进程的关系 父子关系、兄弟关系、亲缘关系
运行:占据CPU执行 就绪:进程进入就绪队列等待获取CPU执行,优先级高的先处理,当优先级相同时,轮询处理
阻塞:当有I/0请求时,释放CPU的使用权,因为IO操作比较耗时,此时进入阻塞状态,如果IO操作结束后,状态切换为就绪态(进入就绪队列等待获取CPU执行)
?Linux进程常用的五种状态
运行状态(TASK_RUNNING)
可中断睡眠状态(TASK_INTERRUPTIBLE)
不可中断睡眠状态(TASK_UNINTERRUPTIBLE)
暂停状态(TASK_STOPPED)
僵死状态(TASK_ZOMBIE)—僵尸进程
僵尸进程:子进程已经结束,但是父进程并没有回收其资源,此时的子进程就是一个僵尸进程。使用wait和waitpid函数可以解决这个问题
孤儿进程:父进程已经结束,但是子进程仍在运行。这时候子进程就是孤儿进程
守护进程:(相当于windows的服务程序)一种脱离终端,在后台运行的一种进程。终端的开关与他无关
?进程标识符pid 每个进程都有一个独一无二的进程标识符,标志符大于等于0,0号进程是内核进程,它创建1号进程,1号进程创建了2号进程 进程id的范围如下所示在这里插入图片描述 ?创建进程
分配id,分配PCB 分配地址空间 拷贝父进程的进程空间 将子进程置为就绪状态 放到就绪队列
?程序转换为进程
内核将程序读入内存,为程序分配内存空间 内核为该进程分配进程标识符pid和其他所需资源 内核为该进程保存PID及相应的状态信息,把进程放到运行队列中等待执行.程序转化为进程后就可以被操作系统的调度程序调度执行了
?销毁进程
回收各种资源 、记录系统日志、将进程换出内存,置为僵尸状态、转存储调度
?进程的终止方式 有5种方式使进程终止
1、从main返回
2、调用exit
3、调用_exit
4、调用abort
5、由一个信号终止
进程在终止的时候,系统会释放进程所拥有的资源,例如内存、文件描述符,内核结构等。
exit:退出时清理资源和IO缓冲区中的内容
_exit:不清理IO缓冲区中的内容

案例1:

#include<stdio.h>
#include<unistd.h> 
#include<sys/types.h> 
int main()
{
    int n = 10;    pid_t pid = getpid();
    pid_t ppid = getppid();    
    while(1)
    {
        printf("pid=%d,ppid=%d\n",pid,ppid);
        printf("&n=0x%x\n",&n);        
        sleep(5);
    }    
    return 0;
}
 

在这里插入图片描述
fork
进程复制,创建子进程
fork() 函数不需要参数,但返回两次,返回值有三种情况:
(1)对于父进程,fork函数返回新的子进程的ID。
(2)对于子进程,fork函数返回0。
(3)如果出错,fork函数返回-1。
fork()的特点是执行一次,返回两次。在父进程和子进程中返回的是不同的值,父进程返回的是子进程的ID号,而子进程中则返回0。
案例2:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
 int n = 10;
 //进程复制
  int pid = fork();
  //fork失败
    if(-1 == pid)
    {
        perror("fork");
        exit(-1);
    }
if(0 == pid)
    {
    //子进程
    printf("child pid=%d,ppid=%d\n",getpid(),getppid());
     printf("&n=0x%x\n",&n);
     exit(0);
     }
     else if(pid > 0)
    {
    //父进程
    //让当前进程休眠1秒
       //sleep(1);
       //等待进程结束
       //wait(NULL);
       printf("father pid=%d,ppid=%d\n",getpid(),getppid());
        printf("&n=0x%x\n",&n);
         wait(NULL);
         }
         return 0;
         }

在这里插入图片描述
情况1:产生孤儿进程
在这里插入图片描述

情况2:sleep(1)后产生的结果
在这里插入图片描述情况3:使用wait()
1.wait在前
在这里插入图片描述

2.wait在后
在这里插入图片描述
案例3:
子进程会拷贝父进程的所有资源,变量。
注意:子进程拷贝了父进程数据空间、堆、栈等资源的副本,
父子进程间不共享这些存储空间,共享的空间只有代码段,
子进程修改一个全局变量,父进程的这个全局变量不会改变,因为是一个副本。

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
int main()
{
    int n = 1;
//如果fork成功,则返回两次
    pid_t pid = fork();
 if(-1 == pid)
    {
        perror("fork:");
        exit(-1);
    }
 if(pid == 0)
    {
    //子进程
 while(1)
        {
            n++;
 printf("child pid=%d,ppid=%d\n",getpid(),getppid());
 sleep(1);
        }
exit(0);
    }
    else
    {
    //父进程
     while(1)
        {
            printf("father pid=%d,n=%d\n",getpid(),n);
 sleep(1);
        }
}
printf("main ending!\n");
return 0}

在这里插入图片描述
在这里插入图片描述
强制结束父进程,则1号接管子进程
在这里插入图片描述
在这里插入图片描述
?子进程从父进程拷贝的内容主要有以下
用户号UIDS和用户组号GIDS
环境Environment
堆栈
共享内存
打开文件的描述符
执行时关闭(Close-on-exec)标志
信号(Signal)控制设定
进程组号
当前工作目录
根目录
文件方式创建屏蔽字
资源限制
控制终端
?子进程独有
进程号PID
不同的父进程号
自己的文件描述符和目录流的拷贝
子进程不继承父进程的进程正文(text),数据和其他锁定内存(memory locks)
不继承异步输入和输出
父进程和子进程拥有独立的地址空间
案例4:

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

/*全局变量*/
char *msg = "shenlan";
int g_value = 0;
int main()
{
 printf("%s\n", msg);
int val = 0;
printf("uid:%d,euid:%d,gid:%d,egid:%d\n", getuid(), geteuid(), getgid(), getegid());
pid_t id = fork();
if (id < 0)
 {
  printf("fork error\n");
  exit(1);
 }
 else if (id == 0)
 {
 //子进程执行代码
  val++;
  g_value++;
printf("child:pid:%d,ppid:%d,val:%d,&val:0x%x,g_value:%d,&g_value:0x%x\n",
   getpid(), getppid(), val, &val, g_value, &g_value);
   
}
 else
 {
 //父进程执行代码
sleep(1);
printf("father:pid:%d,ppid:%d,val:%d,&val:0x%x,g_value:%d,&g_value:0x%x\n",
   getpid(), getppid(), val, &val, g_value, &g_value);
sleep(3);
}
return 0;
}

在这里插入图片描述
案例5:

#include <stdio.h>  
#include <sys/types.h>  
#include <unistd.h>  
int main(void)  
{  
 int i;  
 for(i=0; i<2; i++){  
  fork();  
  printf("-");  
 }
 return 0;  
} 
```![在这里插入图片描述](https://img-blog.csdnimg.cn/20191011174459698.png)
案例6:

```cpp
/*
父子进程的文件描述符可以共享,但是要在fork之前打开,并在公有代码中关闭文件
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *args[])
{
 // 打开文件描述符:在fork之前打开才能让父进程和子进程共享
 int fd = open("data.txt", O_RDONLY);

// 判断文件打开是否成功
 if (fd == -1)
 {
  printf("File open failed : %s\n", strerror(errno));
 }
// 定义读取文件的缓冲区
 char buf[1024];
//读取到的字节数
 int nread;
// 执行fork函数
 pid_t pd = fork();
 // 判断fork是否成功
 if (pd == -1)
 {
  printf("fork failed : %s\n", strerror(errno));
 }
// 通过if...else...执行父子进程的特有代码
 if (pd > 0)
 {
  sleep(5);
//清空缓冲区内存
  memset(buf, 0, sizeof(buf));
  // 读取文件内容
  nread = read(fd, buf, 7);
buf[nread] = '\0';
  //将读取到的内容显示到屏幕上
  printf("%s\n", buf);
printf("father fd = %d\n", fd);
//关闭文件描述符
  close(fd);
}
else
{
  //清空缓冲区内存
  memset(buf, 0, sizeof(buf));
  // 读取文件内容
  nread = read(fd, buf, 5);
buf[nread] = '\0';
  //将读取到的内容显示到屏幕上
  printf("%s\n", buf);
printf("son fd = %d\n", fd);
//关闭文件描述符
  close(fd);
 }
printf("process [%d] ending!\n", getpid());
return 0;
}

在这里插入图片描述
vfork() 函数和 fork() 函数(fork()如何使用,请点此链接)一样都是在已有的进程中创建一个新的进程,但它们创建的子进程是有区别的。
fork(): 父子进程的执行次序不确定。
vfork():保证子进程先运行,在它调用 exec(进程替换) 或 exit(退出进程)之后父进程才可能被调度运行。
fork(): 子进程拷贝父进程的地址空间,子进程是父进程的一个复制品。
vfork():子进程共享父进程的地址空间(准确来说,在调用 exec(进程替换) 或 exit(退出进程) 之前与父进程数据是共享的)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言与Linux相关的知识点包括: 1. 编译和链接:在Linux中,使用gcc编译器可以将C语言源代码编译成可执行文件。编译过程包括预处理、编译、汇编和链接。 2. 系统调用:Linux提供了一组系统调用接口,用于访问操作系统的功能,例如文件操作、进程管理等。C语言可以使用系统调用接口来与操作系统交互。 3. 进程和线程:Linux是一个多任务操作系统,支持同时运行多个进程和线程。C语言可以使用fork()函数创建子进程,使用pthread库创建线程。 4. 文件操作:Linux提供了丰富的文件操作函数,如打开、读取、写入、关闭文件等。C语言可以使用这些函数来进行文件的读写操作。 5. 网络编程:Linux支持网络编程,可以使用C语言编写网络应用程序。常用的网络编程库包括socket、libcurl等。 6. 内存管理:Linux提供了内存管理机制,包括动态内存分配和释放。C语言可以使用malloc()和free()函数来进行动态内存管理。 7. 信号处理:Linux中的进程间通信机制之一是信号。C语言可以使用signal()函数来注册信号处理函数,并对接收到的信号进行处理。 8. 多线程同步:在多线程编程中,需要考虑线程之间的同步和互斥。Linux提供了互斥锁、条件变量等同步机制,C语言可以使用这些机制来实现线程同步。 9. 进程间通信:Linux提供了多种进程间通信机制,如管道、消息队列、共享内存等。C语言可以使用这些机制实现进程间的数据交换和通信。 10. Shell脚本编程:Linux中的Shell脚本是一种用于批处理和自动化任务的脚本语言。C语言可以与Shell脚本进行交互,实现更复杂的系统管理功能。 以上是C语言与Linux相关的一些知识点,希望对你有帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值