8.1.随机数和伪随机数
(1)随机数是随机出现的没有任何规律的一组数列;真正的完全随机的数列是不存在的(只存在理想情况下);我们平时要用到随机数时一般只能通过一些算法得到1个伪随机数序列;我们平时说到随机数,基本都指的是伪随机数。
(2)linux中随机数相关API是rand和srand;连续多次调用rand函数可以返回1个伪随机数序列;srand函数用来设置rand获取的伪随机序列的种子。
(3)单纯使用rand重复调用n次,就会得到1个0-RAND_MAX之间的伪随机数,如果需要调整范围,可以得到随机数序列后再进行计算;单纯使用rand来得到伪随机数序列有缺陷,每次执行程序得到的伪随机序列是同1个序列,无法得到其它序列。
(4)rand函数内部的算法其实是通过1个种子(seed),rand内部默认使用1作为seed,每个不同的种子对应不同的算法,如果种子相同,则算法相同,则多次运行同1个程序产生的随机数序列相同;为了每次执行该程序获取的伪随机序列不同,则每次都要提供不同的种子,我们用srand函数来设置种子。
(5)在每次执行程序时,先用srand设置1个不同的种子,然后再多次调用rand获取1个伪随机序列,则每次都得到1个不同的伪随机序列;在实际应用中常规做法是用time函数的返回值来做srand的参数;而在linux系统中其会收集系统中的某些随机发生的事件的时间(譬如移动鼠标或操作触摸屏)作为随机种子去生成随机数序列。
8.2.proc虚拟文件系统
(1)简单的程序使用单步调试;复杂程序通过printf打印信息调试;框架体系程序通过输出log日志记录信息调试;内核程序调试无法使用前面的3种调试方法,因为内核是该3种调试方法的服务提供者,则内核调试面临困境。
(2)linux内核是1个非常庞大和复杂的单独的程序,对于这样的1个程序来说调试是非常复杂的;像kernel这样庞大的项目,给里面添加/更改某个功能是非常麻烦的,因为新添加的某个功能可能会影响其它已有的功能;早期内核版本中尽管调试很麻烦,但是高手们可以凭借个人超凡脱俗的能力去驾驭,但到了2.4左右的版本时,内核调试难度已经非常大了。
(3)为了降低内核调试和学习的难度,内核开发者们在内核中添加了某些属性专门用于调试内核,proc文件系统就是1个尝试;proc文件系统的思路是在内核中构建1个虚拟文件系统/proc,内核运行时将内核中某些关键的数据结构以文件的方式呈现在/proc目录中的某些特定文件中,这样即将不可见的内核中的数据结构以可视化的方式呈现给内核的开发者。
(4)proc文件系统提供给开发者1种调试内核的方法,我们通过实时的观察/proc/xxx文件,来观察内核中特定数据结构的值,在我们添加某个新功能的前后来对比判断该新功能产生的影响对还是不对。
(5)proc目录下的文件大小都是0,因为这些文件本身并不存在于硬盘中,其不是1个真实文件,它只是一个接口,当我们去读取该文件时,其实内核并不是去硬盘上找该文件,而是映射为内核内部中的某个数据结构被读取并且格式化成字符串输出到该文件中,则尽管我们看到的还是1个文件内容字符串,和普通文件一样的,但实际上文件的内容是实时读取内核中数据结构得来的,而不是从硬盘中读取来的。
(6)常用proc中的文件有/proc/cmdline,/proc/cpuinfo,/proc/devices,/proc/interrupts等。
(7)proc文件系统的使用通常有3种方式;cat以手工查看(譬如查看操作系统版本cat/proc/version);譬如查看当前操作系统安装了哪些驱动设备cat/proc/devices);在程序中可以通过文件IO访问;在shell程序中用cat命令结合正则表达式来获取并处理内核信息。
8.3.sys虚拟文件系统
(1)sys文件系统本质上和proc文件系统相同,都是虚拟文件系统,都在根目录下有个目录(1个是/proc目录,另1个是/sys目录),则它们都不是硬盘中的文件,都是内核中的数据结构的可视化接口。
(2)/proc中的文件只能读,但/sys中的文件可以读写;读/sys中的文件就是获取内核中数据结构的值,而写入/sys中的文件就是设置内核中的数据结构的元素的值。
(3)历史上刚开始先有/proc文件系统,人们希望通过这种技术来调试内核,实际做出来后确实很有用,所以很多内核开发者都去内核调价代码向/proc目录中写文件,而且刚开始的时候内核管理者对proc目录的使用没有进行统一规划,导致后面proc里面的东西又多又杂乱。
(4)后期因为proc中的内容太多太乱缺乏统一规划,于是乎又添加了sys目录;sys文件系统一开始就做了很好的规划和约定,则后来使用sys目录时有了规矩。
8.rand_srand
/*
* 公司:XXXX
* 作者:Rston
* 博客:http://blog.youkuaiyun.com/rston
* GitHub:https://github.com/rston
* 项目:随机数和proc和sys文件系统
* 功能:简单延时产生随机数的方法。
*/
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int i = 0, val = 0;
// 输出RAND_MAX的值
printf("RAND_MAX = %d.\n", RAND_MAX); // RAND_MAX = 2147483647.
// 产生随机数,需注意该程序在1s时间只能运行1次,否则将得到两组相同的随机数列
srand(time(NULL));
for (i=0; i<5; i++)
{
val = rand();
printf("%d ", val);
printf("%d ", val % 6);
}
printf("\n");
return 0;
}
8.io_proc
/*
* 公司:XXXX
* 作者:Rston
* 博客:http://blog.youkuaiyun.com/rston
* GitHub:https://github.com/rston
* 项目:随机数和proc和sys文件系统
* 功能:通过文件IO使用proc虚拟文件系统。
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
int fd = -1;
char buf[512] = {0};
if (argc != 2)
{
printf("usage: %s -v|-d\n", argv[0]);
exit(-1);
}
if (!strcmp(argv[1], "-v"))
{ // 查看当前操作系统版本信息
fd = open("/proc/version", O_RDONLY);
if (fd < 0)
{
perror("open error");
exit(-1);
}
read(fd, buf, sizeof(buf));
printf("version is %s", buf);
}
else if (!strcmp(argv[1], "-d"))
{ // 查看当前操作系统安装了哪些驱动设备
memset(buf, 0, sizeof(buf));
fd = open("/proc/devices", O_RDONLY);
if (fd < 0)
{
perror("open error");
exit(-1);
}
read(fd, buf, sizeof(buf));
printf("devices is %s", buf);
}
return 0;
}