我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系;

截至目前,我们所认识的计算机,都是有一个个的硬件组件组成:
关于冯诺依曼强调几点:
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:

计算机管理硬件:
task_struct-PCB的一种
task_ struct内容分类

可以在内核源代码里找到它。所有运行在系统里的进程都以task_struct链表的形式存在内核里;
进程的信息可以通过 /proc 系统文件夹 查看

- #include
- #include
- #include
- int main()
- {
- while(1)
- {
- sleep(1);
- }
- return 0;
- }

- #include
- #include
- #include
- int main()
- {
- printf("pid: %d\n", getpid());
- printf("ppid: %d\n", getppid());
- return 0;
- }
- #include
- #include
- #include
- int main()
- {
- int ret = fork();
- printf("hello proc : %d!, ret: %d\n", getpid(), ret);
- sleep(1);
- return 0;
- }
- #include
- #include
- #include
- int main()
- {
- int ret = fork();
- if(ret < 0)
- {
- perror("fork");
- return 1;
- }
- else if(ret == 0)
- { //child
- printf("I am child : %d!, ret: %d\n", getpid(), ret);
- }
- else
- {
- //father
- printf("I am father : %d!, ret: %d\n", getpid(), ret);
- }
- sleep(1);
- return 0;
- }

- /*
- * The task state array is a strange "bitmap" of
- * reasons to sleep. Thus "running" is zero, and
- * you can test for combinations of others with
- * simple bit tests.
- */
-
- static const char * const task_state_array[] = {
- "R (running)", /* 0 */
- "S (sleeping)", /* 1 */
- "D (disk sleep)", /* 2 */
- "T (stopped)", /* 4 */
- "t (tracing stop)", /* 8 */
- "X (dead)", /* 16 */
- "Z (zombie)", /* 32 */
- };

ps aux / ps axj 命令

来一个创建维持30秒的僵死进程例子:
- #include
- #include
- int main()
- {
- pid_t id = fork();
- if(id < 0)
- {
- perror("fork");
- return 1;
- }
- else if(id > 0)
- {
- //parent
- printf("parent[%d] is sleeping...\n", getpid());
- sleep(30);
- }
- else
- {
- printf("child[%d] is begin Z...\n", getpid());
- sleep(5);
- exit(EXIT_SUCCESS);
- }
- return 0;
- }
- #include
- #include
- #include
- int main()
- {
- pid_t id = fork();
- if(id < 0)
- {
- perror("fork");
- return 1;
- }
- else if(id == 0)
- {
- //child
- printf("I am child, pid : %d\n", getpid());
- sleep(10);
- }
- else
- {
- //parent
- printf("I am parent, pid: %d\n", getpid());
- sleep(3);
- exit(0);
- }
- return 0;
- }
在linux或者unix系统中,用ps –l命令则会类似输出以下几个内容:

容易注意到其中的几个重要信息,有下:
用top命令更改已存在进程的nice:



1. 创建hello.c文件;
- #include
- int main()
- {
- printf("hello world!\n");
- return 0;
- }
2. 对比./hello执行和之间hello执行;
3. 为什么有些指令可以直接执行,不需要带路径,而我们的二进制程序需要带路径才能执行;
4. 将我们的程序所在路径加入环境变量PATH当中, export PATH=$PATH:hello程序所在路径
5. 对比测试
1. 用root和普通用户,分别执行 echo $HOME ,对比差异 . 执行 cd ~; pwd ,对应 ~ 和 HOME 的关系


每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串
- #include
- int main(int argc, char *argv[], char *env[])
- {
- int i = 0;
- for(; env[i]; i++){
- printf("%s\n", env[i]);
- }
- return 0;
- }
- #include
- int main(int argc, char *argv[])
- {
- extern char **environ;
- int i = 0;
- for(; environ[i]; i++)
- {
- printf("%s\n", environ[i]);
- }
- return 0;
- }
libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明;
- #include
- #include
- int main()
- {
- printf("%s\n", getenv("PATH"));
- return 0;
- }
常用getenv和putenv函数来访问特定的环境变量
- #include
- #include
- int main()
- {
- char * env = getenv("MYENV");
- if(env){
- printf("%s\n", env);
- }
- return 0;
- }
直接查看,发现没有结果,说明该环境变量根本不存在
实验

来段代码感受一下
- #include
- #include
- #include
- int g_val = 0;
- int main()
- {
- pid_t id = fork();
- if(id < 0)
- {
- perror("fork");
- return 0;
- }
- else if(id == 0)
- {
- //child
- printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
- }
- else
- {
- //parent
- printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
- }
- sleep(1);
- return 0;
- }
输出
- //与环境相关,观察现象即可
- parent[2996]: 0 : 0x80497a9
- child[2997]: 0 : 0x80497a9
我们发现,输出出来的变量值和地址是一模一样的,很好理解,因为子进程按照父进程为模版,父子并没有对变量进行进行任何修改;可是将代码稍加改动:
- #include
- #include
- #include
- int g_val = 0;
- int main()
- {
- pid_t id = fork();
- if(id < 0)
- {
- perror("fork");
- return 0;
- }
- else if(id == 0)
- {
- //child,子进程肯定先跑完,也就是子进程先修改,完成之后,父进程再读取
- g_val=100;
- printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
- }
- else
- {
- //parent
- sleep(3);
- printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
- }
- sleep(1);
- return 0;
- }
输出结果:
- //与环境相关,观察现象即可
- child[3056]: 100 : 0x80347f4
- parent[3055]: 0 : 0x80347f4
我们发现,父子进程,输出地址是一致的,但是变量内容不一样!能得出如下结论:
所以之前说"程序的地址空间"是不准确的,准确的应该说成 "进程地址空间",那该如何理解?看图:

说明:



上图是Linux2.6内核中进程队列的数据结构