.1. Locks
Esse documento representa parte dos meus estudos acerca do Livro - Operational Systems Three Easy Pieces, de dominio publico.
Locks
Uma trava/lock eh apenas uma variavel que delimita uma regiao critica. Essa variavel armazena o estado da trava, seja unlocked ou locked.
A ideia eh um tanto quanto simples. Quando uma thread acessa uma lock via lock(), ele “retem” (vira o owner) a lock para si e so desfaz a trava quando chamado por unlock(). Se outra thread tentar acessar o codigo dentro da regiao critica ele nao conseguira prosseguir.
Pthread Locks
Nome que a Lib POSIX usa para uma lock eh mutex (mutual exclusion).
exemplo:
Tecnicas de criação de um lock
desativando interrupções
Uma das soluções mais antigas para promover exclusão mutua era apenas desabilitar interrupções em regiões criticas. Neste caso, se o ambiente fosse de apenas um processador, parar as interrupções (com algum controle especial) habilitam a exclusão.
[!failure] problemas
- necessidade de privilegios para todas as threads.
- nao permite ambientes multiprocessador (ja que parar interrupcao so para um processador por vez)
- pode-se perder interrupcoes
Spin-lock (test and set)
Test-and-set ou atomic exchange: uma instrução com suporte em hardware:
int TestAndSet(int *old_ptr, int new) {
int old = *old_ptr; // fetch old value at old_ptr
*old_ptr = new; // store 'new' into old_ptr
return old; // return the old value
}
typedef struct __loct_t {
int flag;
}
void init(lock_t *lock) {
// 0: lock is available, 1: lock is held
lock->flag = 0;
}
void lock(lock_t *lock) {
while (TestAndSet(&lock->flag, 1) == 1)
; // spin-wait (do nothing)
}
void unlock(lock_t *lock) {
lock->flag = 0;
}Esse metodo cicla até o lock estar disponível, ou seja, checa toda vez (quase como o polling, visto adiante, para IO).
Compare and Swap
int CompareAndSwap(int *ptr, int expected, int new) {
int actual = *ptr;
if (actual == expected)
*ptr = new;
return actual;
}checa se o valor de ptr é igual ao esperado. Se for, troca, se não, devolveo antigo valor de memoria.
…
Usando Filas: Sleeping ao inves de Spinning
Usaremos a seguinte estrutura:
typedef struct __lock_t {
int flag;
int guard;
queue_t *q;
} lock_t;
void lock_init(lock_t *m) {
m->flag = 0;
m->guard = 0;
queue_init(m->q);
}
void lock(lock_t *m) {
while (TestAndSet(&m->guard, 1) == 1); //acquire guard lock by spinning
if (m->flag == 0) {
m->flag = 1; // lock is acquired
m->guard = 0;
} else {
queue_add(m->q, gettid());
m->guard = 0;
park();
}
}
void unlock(lock_t *m) {
while (TestAndSet(&m->guard, 1) == 1); //acquire guard lock by spinning
if (queue_empty(m->q))
m->flag = 0; // let go of lock; no one wants it
else
unpark(queue_remove(m->q)); // hold lock (for next thread!)
m->guard = 0;
}Two Phase Locks
Uso real: o lock gira parcialmente e depois dorme.
Avaliando um lock
Correctness: garante exclusão mutua. Fairness: evita starvation performance: custo de CPU e mem.

