This type of trade-off is common in systems; you can’t have your cake and eat it too4

virtualization, concurrency and persistence

程序运行时发生什么?

一个正在运行的程序会做一件非常简单的事情:执行指令。处理器从内存中获取(fetch)一条指令,对其进行解码(decode)(弄清楚这是哪条指令),然后执行(execute)它(做它应该做的事情,如两个数相加、访问内存、检查条件、跳转到函数等)

2.1 虚拟化 CPU

操作系统负责提供一种假象 illusion, 将单个 CPU 转换为看似无限多的 CPU,即 virtualizing the CPU

2.2 虚拟化内存

内存就是一个字节数组,要 read 内存,就必须指定一个 address, 才能访问那里的数据,要写入 write 或 更新 update,需指定写入给定地址的数据

2.3 并发 concurrency

You can think of a thread as a function running whithin the same memory space as other functions, with more than one of them active at a time. 你可以将线程看成与其他函数在同一内存空间中运行的函数,并且每次都有多个线程处于活动状态

#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include "common_threads.h"

volatile int counter = 0;
int loops;

void *worker(void *arg) {
	int i;
	for (i = 0; i < loops; i++) {
		counter++;
	}
	return NULL;
}

int main(int argc, char *argv[]) {
	if (argc != 2) {
		fprintf(stderr, "usage: threads <value>\\n");
		exit(1);
	}
	loops = atoi(argv[1]);
	pthread_t p1, p2;
	printf("Initial value: %d\\n", counter);
	Pthread_create(&p1, NULL, worker, NULL);
	Pthread_create(&p2, NULL, worker, NULL);
	Pthread_join(p1, NULL);
	printf("Final value : %d\\n", counter);
	return 0;
}

// ./thread 100000
// Initial value : 0
// Final value : 143012 // huh??
// ./thread 100000
// Initial value : 0
// Final value : 137298 // what the??

In this example, each thread starts running in a routine called worker(), in which it simply increments a counter in a loop for loops number of times.

上面的程序中的关键部分是增加共享计数器的地方,它需要3条指令:一条将计数器的值从内存加载到寄存器,一条将其递增,另一条将其保存回内存。因为这3条指令并不是以原子方式(atomically)执行(所有的指令一次性执行)的,所以奇怪的事情可能会发生

2.4 持久性

一个进行 I/O 的程序: create a file that contains the string "hello world"