246 lines
6.1 KiB
Markdown
246 lines
6.1 KiB
Markdown
- Spin Lock Implement
|
|
id:: 6436aafd-c85f-414c-8aee-acdc71e9138e
|
|
- ```c
|
|
void lock(lock_t *lock) {
|
|
while (TestAndSet(&lock->status, 1) == 1);
|
|
}
|
|
void unlock(lock_t *lock) { lock->status = 0; }
|
|
```
|
|
- Test-And-Set Code Description
|
|
id:: 6436af87-3f1b-4ee8-a2c8-4de0f1961f1a
|
|
- ```c
|
|
int TestAndSet(int *old_ptr, int new) {
|
|
int old = *old_ptr;
|
|
*old_ptr = new;
|
|
return old;
|
|
}
|
|
```
|
|
- Ticket Lock Implement
|
|
id:: 6436af5c-0000-4bfb-9a27-1d7cf0a830db
|
|
- ```C
|
|
struct lock_t{
|
|
int ticket;
|
|
int turn;
|
|
};
|
|
void lock(lock_t *lock) {
|
|
int myturn = FetchAndAdd(&lock->ticket);
|
|
// atomically allocate a ticket as the thread's turn
|
|
while (lock->turn != myturn) ;
|
|
// wait for its turn
|
|
}
|
|
void unlock(lock_t *lock) {
|
|
lock->turn += 1;
|
|
}
|
|
```
|
|
- Lock with Queue Implement
|
|
id:: 6436b05f-2873-4af4-952c-86d82685b583
|
|
- ```C
|
|
struct lock_t{
|
|
int lk;
|
|
int guard; // spin lock for the whole lock
|
|
queue_t *q; // control who gets the lock next
|
|
};
|
|
void lock(lock_t *lock) {
|
|
while (TestAndSet(&m->guard, 1) == 1) ;
|
|
if (m->lk == 0) {
|
|
m->lk = 1;
|
|
m->guard = 0;
|
|
}
|
|
else {
|
|
m->q->add(get_tid());
|
|
setpark(); // newly added
|
|
m->guard = 0;
|
|
// ---- wakeup/waiting race ----
|
|
park();
|
|
}
|
|
}
|
|
void unlock(lock_t *lock) {
|
|
while (TestAndSet(&m->guard, 1) == 1) ;
|
|
if (m->q->empty())
|
|
m->flag = 0;
|
|
else
|
|
unpark(m->q->pop()); // should not clear flag here
|
|
// Wake up Only one waiting thread
|
|
m->guard = 0;
|
|
}
|
|
```
|
|
- Producer/Consumer Solution with Condition Variable
|
|
id:: 6436b07d-9279-46bb-9c6b-985eb2324df8
|
|
- ```C
|
|
cond_t empty, fill;
|
|
mutex_t mutex;
|
|
void *producer(void *arg) {
|
|
int i;
|
|
for (i = 0; i < loops; i++) {
|
|
Pthread_mutex_lock(&mutex);
|
|
while (count == MAX)
|
|
Pthread_cond_wait(&empty, &mutex);
|
|
put(i);
|
|
Pthread_cond_signal(&fill);
|
|
Pthread_mutex_unlock(&mutex);
|
|
}
|
|
}
|
|
void *consumer(void *arg) {
|
|
int i;
|
|
for (i = 0; i < loops; i++) {
|
|
Pthread_mutex_lock(&mutex);
|
|
while (count == 0)
|
|
Pthread_cond_wait(&fill, &mutex);
|
|
int tmp = get();
|
|
Pthread_cond_signal(&empty);
|
|
Pthread_mutex_unlock(&mutex);
|
|
printf("%d\n", tmp);
|
|
}
|
|
}
|
|
```
|
|
- Producer/Consumer Solution with Semaphore
|
|
id:: 6436b15a-98b4-49be-8cdf-abefcf7e60b1
|
|
- ```C
|
|
int empty = MAX, full = 0, mutex = 1;
|
|
void *producer() {
|
|
for (int i = 0; i < loops; ++ i) {
|
|
sem_wait(&empty);
|
|
sem_wait(&mutex);
|
|
put(i);
|
|
sem_post(&mutex);
|
|
sem_post(&full);
|
|
}
|
|
}
|
|
void *consumer() {
|
|
for (int i = 0; i < loops; ++ i) {
|
|
sem_wait(&full);
|
|
sem_wait(&mutex);
|
|
int tmp = get();
|
|
sem_post(&mutex);
|
|
sem_post(&empty);
|
|
printf("%d\n", tmp);
|
|
}
|
|
}
|
|
```
|
|
- Dining Philosopher Solution with Semaphore
|
|
id:: 6436bebd-0681-4f94-9d04-4d8e4a554512
|
|
- ```C
|
|
void put_forks(int p) {
|
|
sem_post(&forks[left(p)]);
|
|
sem_post(&forks[right(p)]);
|
|
}
|
|
void get_forks(int p) {
|
|
if (p == 4) {
|
|
sem_wait(&forks[right(p)]);
|
|
sem_wait(&forks[left(p)]);
|
|
} else {
|
|
sem_wait(&forks[left(p)]);
|
|
sem_wait(&forks[right(p)]);
|
|
}
|
|
}
|
|
void philosopher() {
|
|
while (1) {
|
|
think();
|
|
get_forks(p);
|
|
eat();
|
|
put_forks(p);
|
|
}
|
|
}
|
|
```
|
|
- Simple Semaphore Implement
|
|
id:: 6436c47e-dc86-4452-b9b5-4e7997dbfbfb
|
|
- ```C
|
|
struct sem_t{
|
|
int value;
|
|
cond_t cond;
|
|
mutex_t lock;
|
|
};
|
|
void sem_wait(sem_t *sem) {
|
|
mutex_lock(&sem->lock);
|
|
while (s->value <= 0)
|
|
cond_wait(&sem->cond, &sem->lock);
|
|
s->value --;
|
|
mutex_unlock(&sem->lock);
|
|
}
|
|
void sem_post(sem_t *sem) {
|
|
mutex_lock(&sem->lock);
|
|
sem->value ++;
|
|
cond_signal(&sem->cond);
|
|
mutex_unlock(&sem->lock);
|
|
}
|
|
```
|
|
- Compare-And-Swap Code Description
|
|
id:: 6436c5c7-32e7-4071-b909-4fdc14bb479d
|
|
- ```c
|
|
int CompareAndSwap(int *ptr, int expected, int new) {
|
|
int original = *ptr;
|
|
if (original == expected) *ptr = new;
|
|
return orginial
|
|
}
|
|
```
|
|
- Compare-and-swap flavor spin lock
|
|
id:: b7679e9b-aabe-4bd3-8c2c-eb0a23fad491
|
|
- ```C
|
|
void lock(lock_t *lock) {
|
|
while (CompareAndSwap(&lock->status, 0, 1) == 1) ;
|
|
}
|
|
```
|
|
- LL/SC Code Description
|
|
id:: 6436c620-4884-45a7-9273-b7952a6521ae
|
|
- ```c
|
|
int LL(int *ptr) { return *ptr; }
|
|
int SC(int *ptr, int value) {
|
|
if (/*no update to *ptr since LoadLinked to this address*/) {
|
|
*ptr = value;
|
|
return 1; // success!
|
|
} else {
|
|
return 0; // failed to update
|
|
}
|
|
}
|
|
```
|
|
- LL/SC flavor spin lock
|
|
id:: c38274a9-22dd-40e2-b74a-d3a9be63600e
|
|
- very similar to the errant Load/Store lock, but the special instructions here can detect intervening
|
|
```c
|
|
void lock(lock_t *lock) {
|
|
while (true) {
|
|
while (LL(&lock->status) == 1) ; // test
|
|
if (SC(&lock->status, 1) == 1) // set
|
|
break;
|
|
// else retry, in case lock->status is changed
|
|
}
|
|
}
|
|
```
|
|
- Simple Yield Lock Code
|
|
id:: 6436c684-ac4a-4144-9e7e-b4cb8f976c1f
|
|
- ```C
|
|
void lock(lock_t *lock) {
|
|
while (TestAndSet(&lock->status, 1) == 1)
|
|
yield();
|
|
}
|
|
```
|
|
- Fetch-And-Add Code Description
|
|
id:: 6436c66c-807b-4e9d-93ed-b1d9703e6dc2
|
|
- ```C
|
|
int FetchAndAdd(int *ptr) {
|
|
int old = *ptr;
|
|
*ptr = old + 1;
|
|
return old;
|
|
}
|
|
```
|
|
- Readers-Writer Lock Implement
|
|
id:: 6436c668-5be8-4ce1-b701-1f2a00d34cc9
|
|
- ```C
|
|
typedef struct _rwlock_t {
|
|
sem_t guard; // binary semaphore (basic lock)
|
|
sem_t writelock; // allow ONE writer/MANY readers
|
|
int readers; // #readers in critical section
|
|
} rwlock_t;
|
|
void rwlock_acquire_readlock(rwlock_t *rw) {
|
|
sem_wait(&rw->guard);
|
|
if (++rw->readers == 1) sem_wait(&rw->writelock);
|
|
sem_post(&rw->guard);
|
|
}
|
|
void rwlock_release_readlock(rwlock_t *rw) {
|
|
sem_wait(&rw->guard);
|
|
if (--rw->readers == 0) sem_post(&rw->writelock);
|
|
sem_post(&rw->guard);
|
|
}
|
|
void rwlock_acquire_writelock(rwlock_t *rw) { sem_wait(&rw->writelock); }
|
|
void rwlock_release_writelock(rwlock_t *rw) { sem_post(&rw->writelock); }
|
|
``` |