The following problem is a realistic problem recently our project encounters. We now had a solution but imperfectly with limitation, so I put here to anticipate some better ideas.
==============================================
Problem description:
* Goal: A FIFO buffer for one reader and multiple concurrent writers
* Implementation Constraints
1. [VERY IMPORTANT]The code cannot be blocked, which means you cannot use Semaphore Wait or Mutex Wait, etc.
2. The following atomic operations are available to use:
oldValue = AtomicWrite(var, value), AW for short
oldValue = AtomicRead(var), AR for short
oldValue = AtomicIncrementDelta(var, delta), AID for short
oldValue = AtomicDecrementDelta(var, delta), ADD for short
oldValue = AtomicIncrement(var), the same as AtomicIncrementDelta(var, 1), AI for short
oldValue = AtomicDecrement(var), the same as AtomicDecrementDelta(var, 1), AD for short
3. The buffer should follow the FIFO scheme
4. Writes are running concurrently, they can call the following APIs in any unpredictable sequences.
5. There's only one reader.
* Required APIs
Store: Store a chunk of data into buffer
IsEmpty: Check if the buffer is empty
Get: Get a chunk of data into buffer, following the FIFO scheme.
===================================================================
The current solution:
* Constants
S: Number of buffer slots, which is equal to 2^n(n is integer)
* Variables
H: Head index number of the buffer
T: Tail index number of the buffer
N: Number of slots that has data
struct {
f: Flag indicates if the buffer has data
d: data
} B[S]: Buffer slots
F: Buffer state, {Normal, Abnormal}
* Initialization
H = 0
T = 0
N = 0
for i in (0..S): B[i].f = 0
F = Normal
* APIs Algorithm
function Store(data){
while(F = Normal) {
// Increment the tail
oT = AI(T);
// check if the slot is empty
oF = AI(B[oT % S].f);
if (oF >= 1) {
// the slot is full(except when buffer is full, see *limitations*)
AD(B[oT % S].f);
// [!] Check if buffer is full
if (AR(N) >= S) {
// [!] Buffer now is screwed, any further operations on this buffer will fail
F = Abnormal;
}
continue;
} else {
// the slot is empty(except when buffer is full, see *limitations*)
// Set data before increase N
B[oT % S].d = data;
// Increase N, which means there's one more data now
oN = AI(N);
// Check if we're already reach the buffer limit, see *limitation*
if(oN >= S){
// [!] Buffer now is screwed, any further operations on this buffer will fail
F = Abnormal;
}
break;
}
}
return F == Normal?success: failed;
}
function IsEmpty(){
return failed if F == Abnormal;
return AR(N) > 0;
}
function Get(&data){
return failed if F == Abnormal;
if(AR(N)) {
// Get data from head
data = B[H % S]. d;
// First Release the slot
AD(B[H % S].f);
// then Decrease N, which means there's one more slot empty now
AD(N);
// Increase the head
++H;
return success;
} else {
return failed;
}
}
* limitations
When the buffer is full, the buffer state is set to abnormal, further operations will all fail.
Although this limitation may not be a problem since buffer full normally means something wrong already happened.
阅读(1428) | 评论(4) | 转发(0) |