1 # -*- coding: utf-8 -*- 2 import re 3 mem = [x for x in re.split('[\r|\n]', ''' 4 store a 1 5 add a 1 6 jmp -1 7 store a 100 8 add a -1 9 jmp -1 10 '''.lower()) if x != ''] 11 regs = {} # register file: 裝register的櫃子。register: 登記簿. pc: program counter 12 class ProcCxt: # Process Context 13 def __init__(this, pc): this.regs = {'pc' : pc} # this.priority ... 14 proc = [ProcCxt(0), ProcCxt(3)] # 2 processes 15 cpid = 0 # current process index 16 regs = proc[cpid].regs # start from process #0 17 while True: 18 inst = mem[regs['pc']].split() # fetch instruction 取指 19 print(inst, end='\t') 20 op_code = inst[0] # op: operation 21 if op_code == 'store': 22 (reg_name, immd) = inst[1:] 23 regs[reg_name] = int(immd) 24 regs['pc'] += 1 25 elif op_code == 'add': 26 (reg_name, immd) = inst[1:] 27 regs[reg_name] += int(immd) 28 if regs[reg_name] < 0: msb = 1 29 regs['pc'] += 1 30 elif op_code == 'jmp': 31 immd = int(inst[1]) 32 if immd == 0: break 33 regs['pc'] += immd 34 print(regs) 35 if input('Interrupt [y/<Enter>]?').lower() == 'y': 36 proc[cpid].regs = regs 37 cpid = (cpid + 1) & 1 38 regs = proc[cpid].regs 39 print('switched to proc', cpid, regs)
以下內容過分追求簡單,不准確。
CPU有幾十個寄存器。linux kernel按task調度。歷史上還有過batch, job等名詞。ls && date是個job,ls和date是程序,運行起來后叫process,kernel里把process叫task。程序是死的、休眠的,在硬盤上存1萬年還是那些個00101。進程是活的,有上下文。上面的程序A,B,C三個人運行,狀況不一樣——如果他們不是同時按y或Enter鍵的話。Sheldon有了Leonard Nimoy的DNA,種出兩個來,分別在中國和美國生活,中國的會說“英語忒TM難學了”,美國的會說"OMG, there are thousands of characters?"
Windows 95前,Windows沒有搶占式多任務。兩個程序,一個調用get_data從網絡收數據,另一個調用input從鍵盤讀。這兩個函數都是操作系統提供的:
void get_data() { if (data_not_ready) schedule(); ... }
void input() { if (data_not_ready) schedule(); ... }
void schedule() { 選個進程來運行。}
有了時鍾中斷,就可以每隔比如20ms,強行打斷正在執行的進程,重新調度。沒有時鍾中斷的話,網卡鍵盤等外設可能會有中斷。while(1);的程序少,一般總要讀寫下文件吧。操作系統:heiheihei 有機可乘。
所謂進程在CPU上運行…… 其實程序是存在內存里的,多個CPU的多個核共享內存。每個核都是一大塊電路,不同CPU的寄存器是不同的。所謂執行程序,就是寄存器,尤其是PC寄存器變來變去。
用python寫進程調度器自然奇葩,不過linux也不是用匯編寫的啊。當然它的調度器比round robin(圓桌騎士不是亞瑟嗎?)花樣多多了。