Tiny System Design part 2

Jimmy (xiaoke) Shen
1 min readApr 6, 2020

--

Part 1 can be found here.

1188. Design Bounded Blocking Queue

  • Naive and WRONG solution
class BoundedBlockingQueue(object):    def __init__(self, capacity: int):
self._capacity = capacity
self._q = collections.deque([])
def enqueue(self, element: int) -> None:
if len(self._q)==self._capacity:return
self._q.append(element)
def dequeue(self) -> int:
if not self._q:return -1
return self._q.pop()
def size(self) -> int:
return len(self._q)
  • Good solution

This solution is from here.

“The idea is to use two semaphores, pushing and pulling, to maintain the invariants of the queue.
Initially, no thread can dequeue (self.pulling.acquire()) until a thread has enqueued (self.pulling.release()).
When capacity elements have been enqueued, self.pushing.acquire() will block the thread until a dequeue releases the semaphore again.
Additionally, use a Lock so only a single thread can modify the actual queue at once.”

import threading

class BoundedBlockingQueue(object):
def __init__(self, capacity: int):
self.capacity = capacity

self.pushing = threading.Semaphore(capacity)
self.pulling = threading.Semaphore(0)
self.editing = threading.Lock()

self.queue = collections.deque()

def enqueue(self, element: int) -> None:
self.pushing.acquire()
self.editing.acquire()

self.queue.append(element)

self.editing.release()
self.pulling.release()

def dequeue(self) -> int:
self.pulling.acquire()
self.editing.acquire()

res = self.queue.popleft()

self.editing.release()
self.pushing.release()
return res

def size(self) -> int:
return len(self.queue)

As the collections.deque is thread safe, the self.editing is unnecessary.

import threadingclass BoundedBlockingQueue(object):
def __init__(self, capacity: int):
self._capacity = capacity
self._queue = collections.deque()
self._pushing = threading.Semaphore(capacity)
self._pulling = threading.Semaphore(0)
def enqueue(self, element: int) -> None:
self._pushing.acquire()
self._queue.append(element)
self._pulling.release()

def dequeue(self) -> int:
self._pulling.acquire()
res = self._queue.popleft()
self._pushing.release()
return res
def size(self) -> int:
return len(self._queue)

--

--

No responses yet