본문 바로가기
강의/Operating Systems

4. Locks and Condition Variables

by 사향낭 2022. 11. 12.

Locks

  • Locks: an object that can only be owned by a single thread at any given time. Basic operations on a lock:
    • acquire: mark the lock as owned by the current thread; if some other thread already owns the lock then first wait until the lock is free. Lock typically includes a queue to keep track of multiple waiting threads.
    • release: mark the lock as free (it must currently be owned by the calling thread.)
  • Too much milk solution with locks (using Pintos APIs):
struct lock l;
...
lock_acquire(&l);
if (milk == 0) {
  buy_milk();
}
lock_release(&l);
  • A more complex example: producer/consumer.
    • Producers add characters to a buffer
    • Consumers remove characters from the buffer
    • Characters will be removed in the same order added
  • Version 1:
char buffer[SIZE];
int count = 0, putIndex = 0, getIndex = 0;
struct lock l;
lock_init(&l);

void put(char c) {
  lock_acquire(&l);
  count++;
  buffer[putIndex] = c;
  putIndex++;
  if (putIndex == SIZE) {
    putIndex = 0;
  }
  lock_release(&l);
}

char get() {
  char c;
  lock_acquire(&l);
  count--;
  c = buffer[getIndex];
  getIndex++;
  if (getIndex == SIZE) {
    getIndex = 0;
  }
  lock_release(&l);
  return c;
}
  • Version 2 (handle empty/full cases):
char buffer[SIZE];
int count = 0, putIndex = 0, getIndex = 0;
struct lock l;
lock_init(&l);

void put(char c) {
  lock_acquire(&l);
  while (count == SIZE) {
    lock_release(&l);
    lock_acquire(&l);
  }
  count++;
  buffer[putIndex] = c;
  putIndex++;
  if (putIndex == SIZE) {
    putIndex = 0;
  }
  lock_release(&l);
}

char get() {
  char c;
  lock_acquire(&l);
  while (count == 0) {
    lock_release(&l);
    lock_acquire(&l);
  }
  count--;
  c = buffer[getIndex];
  getIndex++;
  if (getIndex == SIZE) {
    getIndex = 0;
  }
  lock_release(&l);
  return c;
}

 

Condition Variables

  • Synchronization mechanisms need more than just mutual exclusion; also need a way tot wait for another thread to do something (e.g., wait for a character to be added to the buffer)
  • Condition variabels: used to wait for a particular state to be reached (e.g. characters in buffer).
    • wait (condition, lock) : atomically release lock, put thread to sleep until condition is signaled; when thread wakes up again, re-acquire lock before returning.
    • signal (condition, lock) : if any threads are waiting on condition, wake up one of them. Caller must hold lock, which must be the same as the lock used in the wait call.
    • broadcast (condition, lock) : same as signal, except wake up all waiting threads.
    • Note: after signal, signaling thread keeps lock, waking thread goes on the queue waiting for the lock.
    • Warning: when a thread wakes up after cond_wait there is no guarantee that the desired condition still exists: another thread might have snuck in.
  • Producer/Consumer, version 3 (with condition variables):
char buffer[SIZE];
int count = 0, putIndex = 0, getIndex = 0;
struct lock l;
struct condition charAdded;
struct condition charRemoved;

lock_init(&l);
cond_init(&charAdded);
cond_init(&charRemoved);

void put(char c) {
  lock_acquire(&l);
  while (count == SIZE) {
    cond_wait(&charRemoved, &l);
  }
  count++;
  buffer[putIndex] = c;
  putIndex++;
  if (putIndex == SIZE) {
    putIndex = 0;
  }
  cond_signal(&charAdded, &l);
  lock_release(&l);
}

char get() {
  char c;
  lock_acquire(&l);
  while (count == 0) {
    cond_wait(&charAdded, &l);
  }
  count--;
  c = buffer[getIndex];
  getIndex++;
  if (getIndex == SIZE) {
    getIndex = 0;
  }
  cond_signal(&charrRemoved, &l);
  lock_release(&l);
  return c;
}

 

Monitors

  • When locks and condition variables are used together like this, the result is called a monitor:
    • A shared data structure
    • A collection of procedures
    • One lock that must be held whenever accessing the shared data (typically each procedure acquires the lock at the very beginning and releases the lock before returning).
    • One or more condition variables used for waiting.
  • There are other synchronization mechanisms besides locks and condition variables.

 

Summary

 

- Lock: 특정 시간에 오직 한 thread만 소유할 수 있는 object (acquire, release)

- Synchronization mechanism은 어떤 일을 하기 위해 또 다른 thread를 기다리는 방법이 필요하다. 여기서는 conditional variable을 사용하였다.

- lock과 conditional variable이 같이 사용될 때의 결과를 monitor라 한다. (a shared data structures, a collection of procedures, one lock must be held whenever accessing the shared data, one or more condition variables used for waiting)

'강의 > Operating Systems' 카테고리의 다른 글

6. Implementing Locks  (0) 2022.11.13
5. Scheduling  (0) 2022.11.13
3. Concurrency  (0) 2022.11.12
2. Threads, Processes, and Dispatching  (0) 2022.11.11
1. Introduction, Operating System History  (0) 2022.10.30

댓글