lec17 - CS 3110 Lectures 17 and 18 Concurrency:...

Info iconThis preview shows pages 1–3. Sign up to view the full content.

View Full Document Right Arrow Icon
CS 3110 Lectures 17 and 18 Concurrency: Producer/Consumer and Thread Pools A classic concurrent programming design pattern is producer-consumer , where processes are designated as either producers or consumers. The producers are responsible for adding to some shared data structure and the consumers are responsible for removing from that structure. Only one party, either a single producer or a single consumer, can access the structure at any given time. Here we consider an example with a shared queue, using a mutex (introduced previously) to protect the queue: let f = Queue.create() and m = Mutex.create () We divide the work of a producer into two parts: produce which simulates the work of creating a product and store which adds the product to the shared queue. produce increments the counter p that it is passed, sleeps for d seconds to simulate the time taken to produce, and outputs a status message: let produce i p d = incr p; Thread.delay d; print_string("Producer " ^ string_of_int(i) ^ " has produced " ^ string_of_int(!p) ^ "\n"); flush stdout store acquires the mutex m , adds to the shared queue, outputs a status message and releases the mutex: let store i p = Mutex.lock m ; Queue.add (i,!p) f ; print_string("Producer " ^ string_of_int(i) ^ " has added its " ^ string_of_int(!p) ^ "-th product\n"); flush stdout; Mutex.unlock m The producer loops n times calling produce and then store , and then sleeping for a random amount of time up to 2.5 seconds. When done looping it outputs a status message. let producer (n,i) = let p = ref 0 and d = Random.float 2. in for j = 1 to n do produce i p d ; store i p ; Thread.delay (Random.float 2.5) done; print_string("Producer " ^ string_of_int(i) ^ " is exiting.\n"); flush stdout The consumer loops n times, acquiring the mutex m , then attempting to take an item from the shared queue. If it succeeds it prints out the item, if not it prints out that it failed to get an item. In either event it unlocks the mutex and then waits a random amount of time upt to 2.5 seconds. When done looping it outputs
Background image of page 1

Info iconThis preview has intentionally blurred sections. Sign up to view the full version.

View Full DocumentRight Arrow Icon
a status message. let consumer (n,i) = for j = 1 to n do Mutex.lock m ; ( try let ip, p = Queue.take f in print_string("Consumer " ^ string_of_int(i) ^ " has taken product (" ^ string_of_int(ip) ^ "," ^ string_of_int(p) ^ ")\n"); flush stdout with Queue.Empty -> print_string("Consumer " ^ string_of_int(i) ^ " has returned empty-handed\n"); flush stdout); Mutex.unlock m ; Thread.delay (Random.float 2.5) done; print_string("Consumer " ^ string_of_int(i) ^ " is exiting.\n"); flush stdout This use of mutual exclusion is very coarse grained. For instance it would be better to be able to have a consumer wait until something is in the queue, rather than returning empty handed. For this we can make use of condition variables, which were introduced previously. Now the store function, store2 signals the condition c to indicate that something is in the queue. let c = Condition.create ()
Background image of page 2
Image of page 3
This is the end of the preview. Sign up to access the rest of the document.

Page1 / 6

lec17 - CS 3110 Lectures 17 and 18 Concurrency:...

This preview shows document pages 1 - 3. Sign up to view the full document.

View Full Document Right Arrow Icon
Ask a homework question - tutors are online