【操作系统】课堂问题记录(PCB进程控制块,syscall,getpid)

【操作系统】课堂问题记录(PCB进程控制块,syscall,getpid)

1.【PCB进程控制块】设计实验验证把同一个程序同时运行两次,拥有两个进程号。

结论:当一个程序同时运行两次时,系统会分配两个不同的进程号(PID)

实验步骤:

(1)编写程序。

编写一个简单的程序,并让其保持运行一段时间。

import time

print("HELLO!I AM STILL RUNNING!")
time.sleep(120)
#设置运行120秒

(2)程序启动两次:在终端/命令行中,分别启动两次该程序。打开两个终端窗口,分别输入以下命令:

python your-filename.py

在这里插入图片描述

(3)查看进程号(PID)

可用以下命令查看正在运行的程序的PID。

在Linux或MacOS中使用ps命令

ps aux | grep your-filename.py

在Windows中可以使用Task Manger 或者tasklist命令

tasklist | findstr your-filename.py

(4)观察输出

【因为我使用的是Windows,所以使用的是tasklist】

在输出中可以看到,同一个程序的多个实例,每个实例有不同的进程号。例如:
在这里插入图片描述

在这个例子中,PID分别为21592和24324,验证了同一个程序在同时运行时被分配了不同的PID。

2.syscall 可调用的参数有哪些?

在操作系统中,系统调用(syscall)是用户程序与操作系统内核交互的主要方式。每个系统调用都有自己的编号和对应的一组参数,参数的类型和数量取决于具体的系统调用。通常来说,系统调用的参数主要包括以下几种类型:


  1. 文件描述符(File Descriptor):
    用于标识一个打开的文件。很多与文件操作相关的系统调用都需要传递文件描述符作为参数,例如 read, write, open, close 等。

  2. 内存地址(Memory Address):
    通常是指向数据缓冲区的指针。比如 read 和 write 系统调用需要传递一个指向缓冲区的指针,用来读入或写出数据。

  3. 大小(Size):
    表示操作的数据大小。比如 read 和 write 需要传递一个整数参数来指明要读/写的数据大小。

  4. 标志(Flags):
    用于控制系统调用的行为。比如 open 系统调用中传递的标志参数可以决定文件是以读、写还是追加的方式打开。

  5. 路径名(Pathname):
    文件操作系统调用通常需要传递文件路径名作为参数,例如 open, unlink, rename 等。

  6. 模式(Mode):
    指定文件权限或者操作模式。比如在 open 系统调用中,可以传递一个模式参数来指定新文件的权限。

  7. 结构体(Structs):
    某些复杂系统调用可能需要传递结构体参数,如 stat 需要一个结构体来存储文件属性信息。

  8. 整数或标识符(Integer or Identifier):
    例如进程 ID、信号编号、用户或组 ID、网络套接字的端口号等。


[!NOTE]

示例

以 read 系统调用为例:

ssize_t read(int fd, void *buf, size_t count);

fd: 文件描述符,标识要读取的文件。

buf: 缓冲区指针,用于存储读取的数据。

count: 读取的字节数。

注意哦,不同操作系统(如 Linux, Windows, macOS)的系统调用接口会有一些差异,因此要具体查看相应系统的文档来了解每个系统调用的参数细节。

在 Linux 中,syscall 的典型用法如下:

#include <unistd.h>                      // 包含 syscall 函数的声明。
#include <sys/syscall.h>              //定义了系统调用号(如 SYS_write)
#include <stdio.h>

int main() {
  long result;

  // 使用 syscall 直接调用 write 系统调用
  result = syscall(SYS_write, STDOUT_FILENO, "Hello, syscall!\n", 16);
  if (result == -1) {
    perror("syscall");
    return 1;
  }

  return 0;
}

1.返回值:
syscall 的返回值通常是系统调用的返回值。对于大多数系统调用,返回值为 -1 表示失败,成功时返回依赖于具体的系统调用(如读取的字节数、写入的字节数等)。

2.错误处理:
使用 perror 打印错误信息,如果系统调用返回 -1,表示调用失败。

[!IMPORTANT]

syscall 使用的注意事项

  1. 参数顺序和类型: 系统调用的参数顺序必须严格按照系统调用的定义传递,并且类型必须匹配。错误的参数会导致系统调用失败,甚至引发程序崩溃。

  2. 系统调用号: 每个系统调用都有一个唯一的系统调用号(在 sys/syscall.h 中定义)。不同的 Linux 内核版本可能会有不同的系统调用号定义,确保使用的系统调用号是当前内核版本支持的。

  3. 系统调用限制: 并不是所有系统调用都可以通过 syscall 来调用。一些特定的系统调用可能需要特殊的权限(如 root 权限)或者有特定的限制。

  4. 性能考虑: 直接使用 syscall 可以绕过标准库层的包装,可能带来一定的性能提升,但代价是代码的可读性和可维护性下降。通常只有在标准库不能满足需求时才直接使用 syscall。

syscall 的典型应用场景

  1. 标准库函数不可用:某些系统调用(如某些特定的 ioctl 调用)没有被封装在标准库中,可以通过 syscall 直接调用。

  2. 性能优化:避免标准库函数的额外开销,直接调用系统调用来减少不必要的封装层。

  3. 系统级别开发:如编写操作系统、驱动程序、系统监控工具等,需要精确控制系统调用的使用场景。

3.syscall—— getpid()的使用

getpid 是一个系统调用函数,用于获取当前进程的进程ID(PID)。进程ID是操作系统用来唯一标识每个进程的整数值。它在多进程编程中非常有用,可以用来区分和管理不同的进程。

getpid 的使用方法

  1. 使用标准库函数 getpid
#include <unistd.h>                            //include <unistd.h>: 头文件包含了 getpid 函数的声明。
#include <stdio.h>

int main() {
  pid_t pid;                                   //pid_t pid: pid_t 是一个数据类型,用于表示进程ID。

  // 获取当前进程的 PID
  pid = getpid();                              //getpid(): 调用 getpid 函数,返回当前进程的进程ID。

  // 输出当前进程的 PID
  printf("Current process ID: %d\n", pid);     //printf("Current process ID: %d\n", pid): 输出进程ID。

  return 0;
}
  1. 使用 syscall 调用 getpid
    在一些情况下,可以通过 syscall 函数来调用 getpid,特别是当你想要避免使用标准库时。
#include <sys/syscall.h> // 包含 SYS_getpid 的定义,这是 getpid 的系统调用号。
#include <unistd.h>
#include <stdio.h>

int main() {
  pid_t pid;

  // 使用 syscall 直接调用 getpid 系统调用
  pid = syscall(SYS_getpid);   // 通过 syscall 函数直接调用 getpid 系统调用。

  // 输出当前进程的 PID
  printf("Current process ID using syscall: %d\n", pid);

  return 0;
}

getpid 的应用场景

  1. 多进程编程:
    在多进程环境中使用 fork 创建子进程时,父进程和子进程的 PID 不同。可以使用 getpid 来区分它们。

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

int main() {
  pid_t pid = fork();

  if (pid == 0) {
    // 子进程
    printf("Child process ID: %d\n", getpid());
  } else {
    // 父进程
    printf("Parent process ID: %d\n", getpid());
  }

  return 0;
}

以上代码中,fork 创建一个子进程,子进程和父进程都会执行 getpid。getpid 会返回当前进程的PID,父进程和子进程的PID不同,因此可以通过它来区分父进程和子进程。

  1. 进程管理:
    在进程管理工具或监控工具中,通过 getpid 可以获取当前进程的 PID,然后将其用于进程管理(如 kill 某个进程、设置某个进程的优先级等)。

  2. 日志记录:
    通过 getpid 记录当前进程的 PID,可以帮助开发者在日志中跟踪是哪一个进程在执行某个操作,特别是在多进程或多线程程序中。

总结来说,getpid 是一个简单而有效的函数,在多进程编程、进程管理和调试中非常有用。它的使用方法也非常直观,通常直接调用即可。

课堂上的疑问解决!!(◍´ಲ`◍)
希望可以帮到大家。 ( ͡◉ ͜ʖ ͡◉)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值