unix环境高级编程 第一章 UNIX基础知识 Go实现代码

news/2024/11/20 7:24:22/

ls命令的Go语言实现

package mainimport ("fmt""os"
)func main() {if len(os.Args) != 2 {panic("参数数量不足")}targetPath := os.Args[1]if dirList, err := os.ReadDir(targetPath); err == nil {for _, dirInfo := range dirList {fmt.Println(dirInfo.Name())}} else {fmt.Println(err.Error())}
}

从标准输入复制到标准输出

package mainimport ("bufio""os""time"
)func main() {reader := bufio.NewReader(os.Stdin)message, _ := reader.ReadString('\n')os.Stdout.WriteString(message)time.Sleep(time.Second)
}

打印进程的pid

package mainimport ("fmt""os"
)func main() {fmt.Printf("hello world from process ID %d\n", os.Getpid())
}

使用fork创建子进程并查看运行结果

package mainimport ("fmt""os""os/exec""syscall"
)func main() {bar := 2foo := "demo"id, _, _ := syscall.Syscall(syscall.SYS_FORK, 0, 0, 0)if id == 0 {bar++cmd := exec.Command("ls")out, _ := cmd.CombinedOutput()fmt.Printf("ls output: %s\n", string(out))fmt.Printf("in child: %d, bar: %v, foo: %v\n", os.Getpid(), bar, foo)} else {foo += "hello"fmt.Printf("in parent: %d, bar: %v, foo: %v\n", os.Getpid(), bar, foo)}
}

获取uid与gid

package mainimport ("fmt""os"
)func main() {fmt.Printf("uid = %d, gid = %d\n", os.Getuid(), os.Getgid())
}

信号signal

中断键 interrupt key, 通常是delete键或者ctrl+c和退出键ctrl+.他们用于中断当前进程.另一种产生信号的方式是调用名为kill的函数.

package mainimport ("fmt""os""os/exec""os/signal""syscall""time"
)func main() {bar := 2foo := "demo"c := make(chan os.Signal, 1)signal.Notify(c, syscall.SIGINT)go func() {for sig := range c {switch sig {case syscall.SIGINT:fmt.Printf("interrupt no: %d\n", syscall.SIGINT)os.Exit(-1)}}}()time.Sleep(5 * time.Second)id, _, _ := syscall.Syscall(syscall.SYS_FORK, 0, 0, 0)if id == 0 {bar++cmd := exec.Command("ls")out, _ := cmd.CombinedOutput()fmt.Printf("ls output: %s\n", string(out))fmt.Printf("in child: %d, bar: %v, foo: %v\n", os.Getpid(), bar, foo)} else {foo += "hello"fmt.Printf("in parent: %d, bar: %v, foo: %v\n", os.Getpid(), bar, foo)}
}

UNIX时间值

UNIX中有两种时间

  1. 日历时间, 从1970年1月1日00:00:00所经过的秒数累计值.这些时间可用于记录文件最近一次的修改时间等.
  2. 进程时间.也成为CPU时间, 用以度量进程使用的cpu资源.进程时间以tick记录.

当度量一个进程的执行时间时, UNIX系统使用三个进程时间值:

  • 时钟时间
  • 用户CPU时间
  • 系统CPU时间

时钟时间又称为墙上时间(wall clock time). 它是进程运行的时间总量, 其值与系统中同时运行的进程数有关. 在我们报告时钟时间时, 都是在系统中没有其他活动时进行度量的.
用户时间是执行用户指令所用的时间量.
系统cpu时间是为该进程执行内核所经历的时间.
例如,只有一个进程执行一个系统服务, 如read或write, 则在内核内执行该服务所花费的时间就计入该进程的系统cpu时间.
用户cpu时间与系统cpu时间的和常被称为CPU时间.
要得到一个程序运行的时钟时间, 用户时间和系统时间很容易, 使用time(1)命令即可.

$ cd /usr/include
$ time grep _POSIX_SOURCE */*.h > /dev/null
real 0m19.81s
user 0m0.43s 
sys 0m4.53s

time函数的输出格式与所使用的shell有关系.

系统调用和库函数

系统调用和库函数之间有重大区别, 但从用户角度看, 其区别并不非常重要.
本书的系统调用和库函数都是以c函数的形式存在.
但我们应当理解, 如果希望的话, 我们可以替换库函数, 但是通常不能替换系统调用.
以内存分配函数malloc为例, 有很多方法可以进行内存管理.如果不喜欢这样的操作方法, 可以定义自己的malloc函数, 它可能将使用sbrk系统调用.
事实上,有很多软件包, 她们实现自己的存储器分配算法, 但仍然使用sbrk系统调用.
下图显示了应用程序, malloc函数和sbrk系统调用的关系
在这里插入图片描述
从图中可见, 两者职责不同,相互分开, 内核中的系统调用分配另外一块空间给进程, 而库函数malloc则管理这一空间.

另外一个可说明系统调用和库函数区别的例子是, UNIX提供决定当前时间和日期的接口.某些操作系统提供一个系统调用以返回时间, 而另一个则返回日期.
任何特殊的处理, 例如正常时制与夏令时的转换, 由内核处理或要求人为干预.
UNIX则不同, 它只提供一个系统调用, 该系统调用返回国际标准时间1970年1月1日0点以来所经过的秒数.对该值的任何解释, 如将其变换为人们可读的, 使用本地时区的时间和日期, 都留给用户进程进行. 在标准c库中, 提供了若干函数来处理大多数情况. 这些库函数处理各种细节, 例如各种夏令时算法.
应用程序可以调用系统调用或库函数, 而很多库函数则会调用系统调用.
系统调用与库函数的另一个差别是: 系统调用通常提供了一种最小接口, 而库函数通常提供比较复杂的功能. 我们从sbrk系统调用和malloc库函数之间的差别中可以看到这一点.
以后比较不带缓冲的IO函数(第三章)与标准IO函数(第五章)时, 还将看到这种差别.
进程控制系统调用(fork,exec和wait)通常由用户的应用程序直接调用. 但为了简化某些常见情况, UNIX系统也提供了一些库函数, 如system和popen.在这里插入图片描述
为了使读者了解大多数程序员应用的unix系统接口, 我们不得不既说明系统调用, 还要介绍某些库函数.
例如若只说明sbrk系统调用, 那么就会忽略很多应用程序使用的malloc库函数.

小结

本节快速浏览了UNIX, 说明了某些以后会多次用到的基本术语.
下一节是关于UNIX标准化的内容, 以及这方面的工作对当前系统的影响.标准, 特别是ANSI C标准和POSIX.1标准将影响本书的余下部分.

课后问题

日历时间存放在有符号32位整型中, 什么时候会溢出(2038年溢出)
如果进程时间存在32位整型数中, 每秒100tick, 经过多少天溢出(248天)

package mainimport "fmt"func main() {var n int32n = 2147483646for i := 0; i < 5; i++ {fmt.Println("n:", n)n += 1}
}

http://www.ppmy.cn/news/98505.html

相关文章

六级备考23天|CET-6|翻译技巧4|2013年官方样题|新年|9:45~11:00

目录 1 PRACTICE ANSWER 2 PRACTICE ANSWER 3 ​ PRACTICE ANSWER 4 PRACTICE ANSWER 5 PRACTICE ANSWER 6 ​ PRACTICE ANSWER ​​​​​​​ 答案整合​​​​​​​ 1 PRACTICE Chinese new year is the Chinese most important traditional festival, wh…

R-Meta分析与【文献计量分析、贝叶斯、机器学习等】多技术融合实践与拓展

Meta分析是针对某一科研问题&#xff0c;根据明确的搜索策略、选择筛选文献标准、采用严格的评价方法&#xff0c;对来源不同的研究成果进行收集、合并及定量统计分析的方法&#xff0c;最早出现于“循证医学”&#xff0c;现已广泛应用于农林生态&#xff0c;资源环境等方面。…

sql语句查询数据库字段和表字段数量

》新建数据库:CREATE DATABASE IF NOT EXISTS 数据库名; 示例&#xff1a;:CREATE DATABASE IF NOT EXISTS test_db; 》进入数据库&#xff1a;use 数据库名称&#xff1b; 示例&#xff1a;use test_db; 》数据库中创建表: create table 表名(字段名 字段类型(长度),字段名 字…

Dom解析与Sax解析的区别

1.Dom解析&#xff1a; Dom解析的时候&#xff0c;首先要把整个文件读取完毕&#xff0c;装载到内存中。然后进行解析&#xff0c;在解析的过程中&#xff0c;你可以直接获取某个节点&#xff0c;进行操作&#xff0c;也可以获取根节点然后进行遍历操作&#xff0c;得到所有的…

Linux 系统编程:内存管理系统调用的深度解析

Linux 系统编程&#xff1a;内存管理系统调用的深度解析 一、引言 (Introduction)1.1 Linux 系统编程概述 (Overview of Linux System Programming)1.2 内存管理的重要性 (Importance of Memory Management)1.3 系统调用的作用 (Role of System Calls) 二、Linux 内存管理基础 …

Allegro操作规范

光绘输出操作规范 1.1添加钻孔表 添加钻孔表的具体步骤为: 1.通过屏幕右边的Visibility选项的Views列表,将Drill层打开 2.将Visibility选项中的PIN和Via选项都选中,见下图所示: 1.2添加钻孔文件 参数设好之后关闭NC Drill/Parameters窗口,输出数控机床钻孔文件的命…

接口自动化一键集成,Jenkins持续集成Allure报告!

目录 前言&#xff1a; 一、接口测试框架选型 二、接口自动化框架封装的设计 2.1 创建测试用例 2.2 执行测试用例 2.3 生成测试报告 三、 实现Jenkins持续集成 3.1 安装Jenkins 3.2 配置Jenkins 3.3 创建Jenkins任务 四、总结 前言&#xff1a; 接口测试作为软件测试中的…

基于Open3D的点云处理4-数据结构Kdtree和Octree

Kdtree Kdtree是一种划分k维数据空间的数据结构&#xff0c;本质也是一颗二叉树&#xff0c;只不过每个节点的数据都是k维&#xff0c;当k1时&#xff0c;就是普通二叉树。 建立Kdtree实际上是一个不断划分的过程&#xff0c;首先选择最sparse的维度&#xff08;一般通过计算…