Before the tutorial session, try your best to solve problems below and be prepared to discuss them at the tutorial session.
wait()
and signal()
semaphore operations are not executed atomically, then mutual exclusion may be violated.deposit(amount)
and withdraw(amount)
. These two functions are passed the amount that is to be deposited or withdrawn from the bank account balance. Assume that a husband and wife share a bank account. Concurrently, the husband calls the withdraw()
function, and the wife calls deposit()
. Describe how a race condition is possible and what might be done to prevent the race condition from occurring. push(item) {
acquire();
if (top < SIZE) {
stack[top] = item;
top++;
}
else
ERROR
release();
}
pop() {
acquire();
if (!is empty()) {
top--;
item = stack[top];
release();
return item;
}
else
ERROR
release();
}
is_empty() {
if (top == 0)
return true;
else
return false;
}
for j = 1 to log 2(N) {
for k = 1 to N {
if ((k + 1) % pow(2,j) == 0) {
values[k] += values[k - pow(2,(j-1))]
}
}
}
This has the effect of summing the elements in the array as a series of partial sums, as shown in the figure below.
After the code has executed, the sum of all elements in the array is stored in the last array location. Are there any race conditions in the above code example? If so, identify where they occur and illustrate with an example. If not, demonstrate why this algorithm is free from race conditions.
compare_and_swap()
for implementing a spinlock is as follows:
void lock spinlock(int *lock) {
while (compare_and_swap(lock, 0, 1) != 0)
; /* spin */
}
A suggested alternative approach is to use the “compare and compare-and-swap” idiom, which checks the status of the lock before invoking the compare_and_swap()
operation. (The rationale behind this approach is to invoke compare_and_swap()
only if the lock is currently available.)
This strategy is shown below:
void lock_spinlock(int *lock) {
while (true) {
if (*lock == 0) {
/* lock appears to be available */
if (!compare_and_swap(lock, 0, 1))
break;
}
}
}
Does this “compare and compare-and-swap” idiom work appropriately for implementing spinlocks? If so, explain. If not, illustrate how the integrity of the lock is compromised.
boolean flag[2]; /* initially false */
int turn;
The structure of process Pi (i == 0 or 1) in Dekker’s algorithm is shown below. The other process is Pj (j == 1 or 0).
while (true) {
flag[i] = true;
while (flag[j]) {
if (turn == j) {
flag[i] = false;
while (turn == j)
; /* do nothing */
flag[i] = true;
}
}
/* critical section */
turn = j;
flag[i] = false;
/* remainder section */
}
compare_and_swap()
instruction. Assume that the following structure defining the mutex lock is available:
typedef struct {
int available;
} lock;
The value (available == 0)
indicates that the lock is available, and a value of 1 indicates that the lock is unavailable. Using this struct, illustrate how the following functions can be implemented using the compare_and_swap()
instruction:
void acquire(lock *mutex)
void release(lock *mutex)
Be sure to include any initialization that may be necessary.
int hits;
mutex_lock hit_lock;
hit_lock.acquire();
hits++;
hit_lock.release();
A second strategy is to use an atomic integer:
atomic_t hits;
atomic_inc(&hits);
Explain which of these two strategies is more efficient.
Discuss the exercises prepared at home