Optimal multithread model

Marc Lehmann schmorp at schmorp.de
Wed Mar 17 01:48:11 CET 2010


On Tue, Mar 16, 2010 at 03:24:32PM +0100, Christophe Meessen <christophe at meessen.net> wrote:
> My rationale is to favor code simplicity and clarity at the cost of some  
> potential performance penalty. This led me to the leader/follower  
> pattern with worker threads handling each request independently.
>
> I was considering using libev as a portable replacement of epoll or  
> kevent which would straightforwardly do the job, but apparently it isn't  
> as simple.

Threads are never simple, programming usually isn't simple.

But I am quite sure that libev, which was designed with threads in mind
(without forcing their use) is better suited for thread programming than
other event libraries, which usually don't give much thoughts about
threads.

And as always, you have to know what you are doing :)

> Marc Lehmann a écrit :
>
>> I would experiment by simply handing the event loop to the next
>> thread in each callback, and acquiring the loop back once finished
>> (stopping/starting of watchers is required here).
>>   
> I'm not sure I understood this correctly. Do you mean I should put the  
> leader/follower polka inside the callback ? This implies the different  

(polka?)

> worker threads call the ev_loop, but just when all the others are  
> inactive, and then in the callback, just synchronize themselves so that  
> only one thread returns from the callback.

That's what I would do in a callback:


   if (operation is fast)
     do it
   else
     {
       unlock_loop-mutex_and_wake_up_another_thread;
       do slow operation;
       acquire_loop_mutex_again;
     }

There is no issue with multiple threads running ev_loop as long as they don't
do so concurrently (inside clalback does not count as inside ev_loop, this is
documented).

The only problem remainign is that ev_loop might block for a long time
waiting for events, while the lock is held.

But that is o.k. with most leader/follower designs. If it is a problem,
then the ev_set_loop_release_cb can be used to free the lock while waiting
- but then you have to make sure you don't recurse into ev_loop while
another thread does the same.

> I don't understand how this can work because we end up with multiple  
> threads executing the ev_loop. This doesn't seem safe because the  
> threads may have context information on their stack on the current  
> ev_loop function which may become incoherent. Did I misunderstood your  
> proposal ?

No, this is explicitly documented to work (see "COROUTINES"):

   (e.g. you can call C<ev_loop> on the same loop from two different
   coroutines, and switch freely between both coroutines running the loop,
   as long as you don't confuse yourself). The only exception is that you
   must not do this from C<ev_periodic> reschedule callbacks.

> Isn't that the same as calling ev_loop with the ONE_SHOT flag ?

ev_loop with that flag does a single iteration, which can result in 0,
1, many callbacks to be invoked. it is not the same as some do_one_event
function found in other event libs (although most of those functions
actually process many events, too).

> Here is an optimized version of the previous skeleton code in which I  
> now use the follower and leader keywords where they belong. I expect  
> this to be a better use of the ev_loop(ONE_SHOT).

I don't think it will sensibly do what you want, as you have no control
over how many callbacks will be invoked. If your callbacks all just queue
the work to some queue, then it is not a problem, but then you will
probably not need to run ev_loop from different threads.

-- 
                The choice of a       Deliantra, the free code+content MORPG
      -----==-     _GNU_              http://www.deliantra.net
      ----==-- _       generation
      ---==---(_)__  __ ____  __      Marc Lehmann
      --==---/ / _ \/ // /\ \/ /      schmorp at schmorp.de
      -=====/_/_//_/\_,_/ /_/\_\



More information about the libev mailing list