Processi, Thread, Multitasking, Multithreading
(Thread-Fu)
Prof. Giovambattista Ianni
Corso di Sistemi Operativi
Aggiornato all’A.A. 2023-24
Quest'opera è distribuita con Licenza
Creative Commons Attribuzione - Non commerciale 4.0 Internazionale.
NO CHATGPT
(for dummies)
Ingredienti
Courtesy of prof. Mario Alviano
READ
WRITE
Ciclo di fetch esteso
Classic fetch
0:IR 🡨 Mem[PC]
PC 🡨 PC+1
Esegui istruzione in IR
Goto 0
Fetch con interrupt
0: IR 🡨 Mem[PC]
PC 🡨 PC+1
Esegui IR
If INTR == 1
oldPC 🡨 PC
PC 🡨 IRQR
Goto 0
IRQR = Interrupt request register: contiene l’indirizzo di memoria
dove si trova la interrupt handling routine
Interrupt
DMA: Direct Memory Access
DMA: RAM accessibile da più entità, non solo la CPU
Esempio di accesso in scrittura in caso di RAM condivisa:
Ciclo di scrittura senza arbitraggio DMA
MAR 🡨 addr
M[MAR] 🡨 MBR
Ciclo di scrittura con arbitraggio DMA
MAR 🡨 addr
HOLD 🡨 1
0: if HLDA == 0
Goto 0
M[MAR] 🡨 MBR
READ
WRITE
DMA transfer
Processi e Thread
Multitasking Collaborativo - I
winProc1(...)
{
... codice ...
return;
}
while(true)
{
Evento e = codaeventi.take();
call(e.destinatario.winProc);
}
Programma
Scheduler
winProcN(...)
{
... codice ...
return;
}
Programmi
Utente
Multitasking collaborativo - II
Multitasking collaborativo - III
Multitasking Non Collaborativo
while(true)
{
Thread t = codaThreadPronti.take();
impostaTimer();
t.load();
t.exec();
t.save();
inserisci t in
codaThreadPronti
oppure in listaThreadinWait;
}
Programma
Scheduler
Multitasking Non Collaborativo
load() e save()
EAX = CCCCCCCC EBX = 7FFD8000
ECX = 00000000 EDX = 00141F25
ESI = 00000000 EDI = 0012FF30
EIP = 00401028 ESP = 0012FEE4
EBP = 0012FF30 EFL = 00000206
CS = 001B DS = 0023 ES = 0023
SS = 0023 FS = 003B GS = 0000 OV=0
UP=0 EI=1 PL=0 ZR=0 AC=0 PE=1 CY=0
ST0 = +0.00000000000000000e+0000
ST1 = +0.00000000000000000e+0000
ST2 = +0.00000000000000000e+0000
ST3 = +0.00000000000000000e+0000
ST4 = +0.00000000000000000e+0000
ST5 = +0.00000000000000000e+0000
ST6 = +0.00000000000000000e+0000
ST7 = +0.00000000000000000e+0000
CTRL = 027F STAT = 0000 TAGS = FFFF
EIP = 00000000 CS = 0000 DS = 0000
EDO = 00000000
Che cosa avviene in exec()
Stato di ogni thread
Ready
Waiting
Running
Passaggi di stato
Ready
Waiting
Running
Comportamento dei thread
Windows 2000-XP-Vista-7-8-10-11
Linux
“I thread non servono a niente”
Scherzavo
Problemi di inconsistenza - 1
int posto[100];
int allocaposto(int p, int codiceutente)
{
if (!posto[p])
return posto[p] = codiceutente;
else
return 0;
}
Problemi di inconsistenza - 2
10: {
...
11: if (!posto[p])
mov eax,dword ptr [ebp+8]
cmp dword ptr [eax*4+4237A4h],0
jne allocaposto+37h (0040b7e7)
return posto[p] = codiceutente;
mov ecx,dword ptr [ebp+8]
mov edx,dword ptr [ebp+0Ch]
mov dword ptr [ecx*4+4237A4h],edx
mov eax,dword ptr [ebp+0Ch]
jmp allocaposto+39h (0040b7e9)
13: else
14: return 0;
0040B7E7 xor eax,eax
15: }
0040B7E9 pop edi
0040B7EA pop esi
0040B7EB pop ebx
0040B7EC mov esp,ebp
0040B7EE pop ebp
0040B7EF ret
10: {
...
11: if (!posto[p])
mov eax,dword ptr [ebp+8]
cmp dword ptr [eax*4+4237A4h],0
jne allocaposto+37h (0040b7e7)
return posto[p] = codiceutente;
mov ecx,dword ptr [ebp+8]
mov edx,dword ptr [ebp+0Ch]
mov dword ptr [ecx*4+4237A4h],edx
mov eax,dword ptr [ebp+0Ch]
jmp allocaposto+39h (0040b7e9)
13: else
14: return 0;
0040B7E7 xor eax,eax
15: }
0040B7E9 pop edi
0040B7EA pop esi
0040B7EB pop ebx
0040B7EC mov esp,ebp
0040B7EE pop ebp
0040B7EF ret
allocaposto(3,27049)
allocaposto(3,11051)
Posto 3
0
Assembly
x86
Problemi di inconsistenza - 2
10: {
...
11: if (!posto[p])
mov eax,dword ptr [ebp+8]
cmp dword ptr [eax*4+4237A4h],0
jne allocaposto+37h (0040b7e7)
return posto[p] = codiceutente;
mov ecx,dword ptr [ebp+8]
mov edx,dword ptr [ebp+0Ch]
mov dword ptr [ecx*4+4237A4h],edx
mov eax,dword ptr [ebp+0Ch]
jmp allocaposto+39h (0040b7e9)
13: else
14: return 0;
0040B7E7 xor eax,eax
15: }
0040B7E9 pop edi
0040B7EA pop esi
0040B7EB pop ebx
0040B7EC mov esp,ebp
0040B7EE pop ebp
0040B7EF ret
10: {
...
11: if (!posto[p])
mov eax,dword ptr [ebp+8]
cmp dword ptr [eax*4+4237A4h],0
jne allocaposto+37h (0040b7e7)
return posto[p] = codiceutente;
mov ecx,dword ptr [ebp+8]
mov edx,dword ptr [ebp+0Ch]
mov dword ptr [ecx*4+4237A4h],edx
mov eax,dword ptr [ebp+0Ch]
jmp allocaposto+39h (0040b7e9)
13: else
14: return 0;
0040B7E7 xor eax,eax
15: }
0040B7E9 pop edi
0040B7EA pop esi
0040B7EB pop ebx
0040B7EC mov esp,ebp
0040B7EE pop ebp
0040B7EF ret
allocaposto(3,27049)
allocaposto(3,11051)
Posto 3
0
Assembly
x86
Problemi di inconsistenza - 2
10: {
...
11: if (!posto[p])
mov eax,dword ptr [ebp+8]
cmp dword ptr [eax*4+4237A4h],0
jne allocaposto+37h (0040b7e7)
return posto[p] = codiceutente;
mov ecx,dword ptr [ebp+8]
mov edx,dword ptr [ebp+0Ch]
mov dword ptr [ecx*4+4237A4h],edx
mov eax,dword ptr [ebp+0Ch]
jmp allocaposto+39h (0040b7e9)
13: else
14: return 0;
0040B7E7 xor eax,eax
15: }
0040B7E9 pop edi
0040B7EA pop esi
0040B7EB pop ebx
0040B7EC mov esp,ebp
0040B7EE pop ebp
0040B7EF ret
10: {
...
11: if (!posto[p])
mov eax,dword ptr [ebp+8]
cmp dword ptr [eax*4+4237A4h],0
jne allocaposto+37h (0040b7e7)
return posto[p] = codiceutente;
mov ecx,dword ptr [ebp+8]
mov edx,dword ptr [ebp+0Ch]
mov dword ptr [ecx*4+4237A4h],edx
mov eax,dword ptr [ebp+0Ch]
jmp allocaposto+39h (0040b7e9)
13: else
14: return 0;
0040B7E7 xor eax,eax
15: }
0040B7E9 pop edi
0040B7EA pop esi
0040B7EB pop ebx
0040B7EC mov esp,ebp
0040B7EE pop ebp
0040B7EF ret
allocaposto(3,27049)
allocaposto(3,11051)
Posto 3
27049
Assembly
x86
Problemi di inconsistenza - 2
10: {
...
11: if (!posto[p])
mov eax,dword ptr [ebp+8]
cmp dword ptr [eax*4+4237A4h],0
jne allocaposto+37h (0040b7e7)
return posto[p] = codiceutente;
mov ecx,dword ptr [ebp+8]
mov edx,dword ptr [ebp+0Ch]
mov dword ptr [ecx*4+4237A4h],edx
mov eax,dword ptr [ebp+0Ch]
jmp allocaposto+39h (0040b7e9)
13: else
14: return 0;
0040B7E7 xor eax,eax
15: }
0040B7E9 pop edi
0040B7EA pop esi
0040B7EB pop ebx
0040B7EC mov esp,ebp
0040B7EE pop ebp
0040B7EF ret
10: {
...
11: if (!posto[p])
mov eax,dword ptr [ebp+8]
cmp dword ptr [eax*4+4237A4h],0
jne allocaposto+37h (0040b7e7)
return posto[p] = codiceutente;
mov ecx,dword ptr [ebp+8]
mov edx,dword ptr [ebp+0Ch]
mov dword ptr [ecx*4+4237A4h],edx
mov eax,dword ptr [ebp+0Ch]
jmp allocaposto+39h (0040b7e9)
13: else
14: return 0;
0040B7E7 xor eax,eax
15: }
0040B7E9 pop edi
0040B7EA pop esi
0040B7EB pop ebx
0040B7EC mov esp,ebp
0040B7EE pop ebp
0040B7EF ret
allocaposto(3,27049)
allocaposto(3,11051)
Posto 3
27049
11051
Assembly
x86
Problemi di inconsistenza - 2
10: {
...
11: if (!posto[p])
mov eax,dword ptr [ebp+8]
cmp dword ptr [eax*4+4237A4h],0
jne allocaposto+37h (0040b7e7)
return posto[p] = codiceutente;
mov ecx,dword ptr [ebp+8]
mov edx,dword ptr [ebp+0Ch]
mov dword ptr [ecx*4+4237A4h],edx
mov eax,dword ptr [ebp+0Ch]
jmp allocaposto+39h (0040b7e9)
13: else
14: return 0;
0040B7E7 xor eax,eax
15: }
0040B7E9 pop edi
0040B7EA pop esi
0040B7EB pop ebx
0040B7EC mov esp,ebp
0040B7EE pop ebp
0040B7EF ret
10: {
...
11: if (!posto[p])
mov eax,dword ptr [ebp+8]
cmp dword ptr [eax*4+4237A4h],0
jne allocaposto+37h (0040b7e7)
return posto[p] = codiceutente;
mov ecx,dword ptr [ebp+8]
mov edx,dword ptr [ebp+0Ch]
mov dword ptr [ecx*4+4237A4h],edx
mov eax,dword ptr [ebp+0Ch]
jmp allocaposto+39h (0040b7e9)
13: else
14: return 0;
0040B7E7 xor eax,eax
15: }
0040B7E9 pop edi
0040B7EA pop esi
0040B7EB pop ebx
0040B7EC mov esp,ebp
0040B7EE pop ebp
0040B7EF ret
allocaposto(3,27049)
allocaposto(3,11051)
Posto 3
11051
Assembly
x86
Esempio con assembly ARM
Quest'opera è distribuita con Licenza
Creative Commons Attribuzione - Non commerciale 4.0 Internazionale.
Problemi di inconsistenza - 2
10: {
...
if (!posto[p])
4006b8: adrp x0, 489000 <_dl_main_map+0xc0>
4006bc: add x0, x0, #0x9c0
4006c0: ldrsw x1, [sp, #12]
4006c4: ldr w0, [x0, x1, lsl #2]
4006c8: cmp w0, #0x0
4006cc: b.ne 4006f8 <_Z11allocapostoii+0x4c>
return posto[p] = codiceutente;
4006d0: adrp x0, 489000 <_dl_main_map+0xc0>
4006d4: add x0, x0, #0x9c0
4006d8: ldrsw x1, [sp, #12]
4006dc: ldr w2, [sp, #8]
4006e0: str w2, [x0, x1, lsl #2]
4006e4: adrp x0, 489000 <_dl_main_map+0xc0>
4006e8: add x0, x0, #0x9c0
4006ec: ldrsw x1, [sp, #12]
4006f0: ldr w0, [x0, x1, lsl #2]
4006f4: b 4006fc <_Z11allocapostoii+0x50>
else
return 0;
4006f8: mov w0, #0x0
}
4006fc: add sp, sp, #0x10
400700: ret
allocaposto(3,27049)
allocaposto(3,11051)
Posto 3
0
Assembly
ARM64
10: {
...
if (!posto[p])
4006b8: adrp x0, 489000 <_dl_main_map+0xc0>
4006bc: add x0, x0, #0x9c0
4006c0: ldrsw x1, [sp, #12]
4006c4: ldr w0, [x0, x1, lsl #2]
4006c8: cmp w0, #0x0
4006cc: b.ne 4006f8 <_Z11allocapostoii+0x4c>
return posto[p] = codiceutente;
4006d0: adrp x0, 489000 <_dl_main_map+0xc0>
4006d4: add x0, x0, #0x9c0
4006d8: ldrsw x1, [sp, #12]
4006dc: ldr w2, [sp, #8]
4006e0: str w2, [x0, x1, lsl #2]
4006e4: adrp x0, 489000 <_dl_main_map+0xc0>
4006e8: add x0, x0, #0x9c0
4006ec: ldrsw x1, [sp, #12]
4006f0: ldr w0, [x0, x1, lsl #2]
4006f4: b 4006fc <_Z11allocapostoii+0x50>
else
return 0;
4006f8: mov w0, #0x0
}
4006fc: add sp, sp, #0x10
400700: ret
Problemi di inconsistenza - 2
10: {
...
if (!posto[p])
4006b8: adrp x0, 489000 <_dl_main_map+0xc0>
4006bc: add x0, x0, #0x9c0
4006c0: ldrsw x1, [sp, #12]
4006c4: ldr w0, [x0, x1, lsl #2]
4006c8: cmp w0, #0x0
4006cc: b.ne 4006f8 <_Z11allocapostoii+0x4c>
return posto[p] = codiceutente;
4006d0: adrp x0, 489000 <_dl_main_map+0xc0>
4006d4: add x0, x0, #0x9c0
4006d8: ldrsw x1, [sp, #12]
4006dc: ldr w2, [sp, #8]
4006e0: str w2, [x0, x1, lsl #2]
4006e4: adrp x0, 489000 <_dl_main_map+0xc0>
4006e8: add x0, x0, #0x9c0
4006ec: ldrsw x1, [sp, #12]
4006f0: ldr w0, [x0, x1, lsl #2]
4006f4: b 4006fc <_Z11allocapostoii+0x50>
else
return 0;
4006f8: mov w0, #0x0
}
4006fc: add sp, sp, #0x10
400700: ret
10: {
...
if (!posto[p])
4006b8: adrp x0, 489000 <_dl_main_map+0xc0>
4006bc: add x0, x0, #0x9c0
4006c0: ldrsw x1, [sp, #12]
4006c4: ldr w0, [x0, x1, lsl #2]
4006c8: cmp w0, #0x0
4006cc: b.ne 4006f8 <_Z11allocapostoii+0x4c>
return posto[p] = codiceutente;
4006d0: adrp x0, 489000 <_dl_main_map+0xc0>
4006d4: add x0, x0, #0x9c0
4006d8: ldrsw x1, [sp, #12]
4006dc: ldr w2, [sp, #8]
4006e0: str w2, [x0, x1, lsl #2]
4006e4: adrp x0, 489000 <_dl_main_map+0xc0>
4006e8: add x0, x0, #0x9c0
4006ec: ldrsw x1, [sp, #12]
4006f0: ldr w0, [x0, x1, lsl #2]
4006f4: b 4006fc <_Z11allocapostoii+0x50>
else
return 0;
4006f8: mov w0, #0x0
}
4006fc: add sp, sp, #0x10
400700: ret
allocaposto(3,27049)
allocaposto(3,11051)
Posto 3
0
Assembly
ARM64
Problemi di inconsistenza - 2
10: {
...
if (!posto[p])
4006b8: adrp x0, 489000 <_dl_main_map+0xc0>
4006bc: add x0, x0, #0x9c0
4006c0: ldrsw x1, [sp, #12]
4006c4: ldr w0, [x0, x1, lsl #2]
4006c8: cmp w0, #0x0
4006cc: b.ne 4006f8 <_Z11allocapostoii+0x4c>
return posto[p] = codiceutente;
4006d0: adrp x0, 489000 <_dl_main_map+0xc0>
4006d4: add x0, x0, #0x9c0
4006d8: ldrsw x1, [sp, #12]
4006dc: ldr w2, [sp, #8]
4006e0: str w2, [x0, x1, lsl #2]
4006e4: adrp x0, 489000 <_dl_main_map+0xc0>
4006e8: add x0, x0, #0x9c0
4006ec: ldrsw x1, [sp, #12]
4006f0: ldr w0, [x0, x1, lsl #2]
4006f4: b 4006fc <_Z11allocapostoii+0x50>
else
return 0;
4006f8: mov w0, #0x0
}
4006fc: add sp, sp, #0x10
400700: ret
10: {
...
if (!posto[p])
4006b8: adrp x0, 489000 <_dl_main_map+0xc0>
4006bc: add x0, x0, #0x9c0
4006c0: ldrsw x1, [sp, #12]
4006c4: ldr w0, [x0, x1, lsl #2]
4006c8: cmp w0, #0x0
4006cc: b.ne 4006f8 <_Z11allocapostoii+0x4c>
return posto[p] = codiceutente;
4006d0: adrp x0, 489000 <_dl_main_map+0xc0>
4006d4: add x0, x0, #0x9c0
4006d8: ldrsw x1, [sp, #12]
4006dc: ldr w2, [sp, #8]
4006e0: str w2, [x0, x1, lsl #2]
4006e4: adrp x0, 489000 <_dl_main_map+0xc0>
4006e8: add x0, x0, #0x9c0
4006ec: ldrsw x1, [sp, #12]
4006f0: ldr w0, [x0, x1, lsl #2]
4006f4: b 4006fc <_Z11allocapostoii+0x50>
else
return 0;
4006f8: mov w0, #0x0
}
4006fc: add sp, sp, #0x10
400700: ret
allocaposto(3,27049)
allocaposto(3,11051)
Posto 3
27049
Assembly
ARM64
Problemi di inconsistenza - 2
10: {
...
if (!posto[p])
4006b8: adrp x0, 489000 <_dl_main_map+0xc0>
4006bc: add x0, x0, #0x9c0
4006c0: ldrsw x1, [sp, #12]
4006c4: ldr w0, [x0, x1, lsl #2]
4006c8: cmp w0, #0x0
4006cc: b.ne 4006f8 <_Z11allocapostoii+0x4c>
return posto[p] = codiceutente;
4006d0: adrp x0, 489000 <_dl_main_map+0xc0>
4006d4: add x0, x0, #0x9c0
4006d8: ldrsw x1, [sp, #12]
4006dc: ldr w2, [sp, #8]
4006e0: str w2, [x0, x1, lsl #2]
4006e4: adrp x0, 489000 <_dl_main_map+0xc0>
4006e8: add x0, x0, #0x9c0
4006ec: ldrsw x1, [sp, #12]
4006f0: ldr w0, [x0, x1, lsl #2]
4006f4: b 4006fc <_Z11allocapostoii+0x50>
else
return 0;
4006f8: mov w0, #0x0
}
4006fc: add sp, sp, #0x10
400700: ret
10: {
...
if (!posto[p])
4006b8: adrp x0, 489000 <_dl_main_map+0xc0>
4006bc: add x0, x0, #0x9c0
4006c0: ldrsw x1, [sp, #12]
4006c4: ldr w0, [x0, x1, lsl #2]
4006c8: cmp w0, #0x0
4006cc: b.ne 4006f8 <_Z11allocapostoii+0x4c>
return posto[p] = codiceutente;
4006d0: adrp x0, 489000 <_dl_main_map+0xc0>
4006d4: add x0, x0, #0x9c0
4006d8: ldrsw x1, [sp, #12]
4006dc: ldr w2, [sp, #8]
4006e0: str w2, [x0, x1, lsl #2]
4006e4: adrp x0, 489000 <_dl_main_map+0xc0>
4006e8: add x0, x0, #0x9c0
4006ec: ldrsw x1, [sp, #12]
4006f0: ldr w0, [x0, x1, lsl #2]
4006f4: b 4006fc <_Z11allocapostoii+0x50>
else
return 0;
4006f8: mov w0, #0x0
}
4006fc: add sp, sp, #0x10
400700: ret
allocaposto(3,27049)
allocaposto(3,11051)
Posto 3
27049
11051
Assembly
ARM64
Voglio vedere il codice misto anche io!
gcc –g miosorgente.cpp
objdump –S miobinario
�Per aarch64 usare l’accoppiata:
aarch64-linux-gnu-gcc
aarch64-linux-gnu-objdump
Race condition
🡪RISULTATI IMPREDICIBILI
non è “Thread-safe”
Esempi di race condition
def bonifico(A : conto, B : conto, s : int):
A.saldo += s
B.saldo -= s
RARO? Seriamente, RARO?
Ho detto che vi troverò
Paradosso del compleanno
Master of race conditions:�Costrutti di sincronizzazione storici
Lock e blocchi synchronized
Condition: notify() e wait()
Blocking queues
Quest'opera è distribuita con Licenza
Creative Commons Attribuzione - Non commerciale 4.0 Internazionale.
Buffering
Riflessioni
53
user
agent
user
agent
1
2
server
3
4
server
5
6
Riflessioni - II
Esempi dove è utilissimo usare una coda (bloccante):
Code Bloccanti – Blocking Queue
Idea
Produttori e consumatori
Altri vantaggi delle BlockingQueues
p = Q.take() # p è privata, non appena ottenuta
print(p) # posso fare quello che voglio a p, nessuno rompe,
p = p+1 # yeeh
…
Q.put(p) # p è privata fino all’inserimento
Deadlock
Quest'opera è distribuita con Licenza
Creative Commons Attribuzione - Non commerciale 4.0 Internazionale.
Deadlock
Livelock
La tempesta perfetta
Evitare il Deadlock
Nested Lockout
import threading
class Lockout:
def __init__(self):
self.a = threading.Lock()
self.b = threading.Lock()
self.c = threading.Condition(self.b)
// T1 esegue questo:
def blocca(self):
self.a.acquire()
self.b.acquire()
while qualcheCondizione:
self.c.wait()
qualcheCondizione = True
self.b.release()
self.a.release()
// T2 esegue questo:
def sblocca(self):
self.a.acquire()
self.b.acquire()
self.qualcheCondizione = False
self.c.notify_all()
self.b.release()
self.a.release()
Starvation
Barriera