Boost logo

Boost :

Subject: Re: [boost] Mutexes claim a Windows event handle
From: Anthony Williams (anthony.ajw_at_[hidden])
Date: 2010-06-03 09:03:35


"Peters, Richard" <richard.peters_at_[hidden]> writes:

> Those 100.000 'objects' are in fact print jobs in a print controller.
> Each job contains the structure describing what the job looks like
> (sheets and pages and such, among with their attributes like stapling or
> how the bitmaps should be rotated), stuff for maintaining progress and
> accounting, a pipeline of objects doing all sorts of manipulations like
> making it a duplex job or creating booklets of it, etc. A job is
> constructed by either ripping a document (for instance postscript) or by
> scanning a document. This ripping or scanning is kind of repeated after
> a user edited the job on the user interface. All the while, the printer
> wants to get information from the job, in order to be able to print the
> job while it's still ripping.

So both the printer and the code creating the job need access to the
same job object. OK.

> Now in this job we have a few mutexes for , but a single mutex for all
> jobs together doesn't cut the case either: a job which is scanning might
> be busy with building a booklet (which is a time-consuming operation),
> and all the while printing of another job must be able to continue.

You shouldn't hold a mutex lock across a time-consuming operation, so
the time-consuming nature of bulding a booklet shouldn't matter.

> Anyway, we ran tests with boost 1.34, and indeed, that version also
> consumes as much handles. We also found that we overestimated our
> maximum job capacity, at about 10.000 jobs, our memory is full, and the
> number of handles is not yet critically high. Any ideas of how to reduce
> our number of mutexes would be welcome, though.

Firstly, the code preparing the data should do as much as possible
without holding any locks. When it has prepared a chunk of data that the
printer should see (e.g. a complete page), it can then acquire the
relevant lock, publish the data and release the lock. This may happen
multiple times for a single job.

Likewise on the printer side --- it should do as much as possible
without holding the lock. When it needs more data it should acquire the
lock, get the data and then release the lock before processing the data.

If you do this then the time spent holding each lock should be
short. You may then be able to get away with a single lock on the
printer.

If you still need more mutexes (possibly because there are lots of jobs
being produced at the same time by multiple threads) then you can create
a table of mutexes. You choose a mutex by hashing a unique job
identifier (e.g. its memory address) to get an index into the
table. This limits the number of mutexes to the size of the mutex table,
but potentially means that on occasion multiple jobs executing
concurrently will use the same mutex.

A similar scheme is to use one mutex per producer thread. The mutex from
the thread that is producing a job is somehow associated with the job,
so the printer can lock that mutex when it needs to access the job
data. Once the job creation has finished the mutex association can be
broken, and the printer need never lock the mutex again. This way
producer threads won't ever contend for the same mutex, so you get all
the benefits of the per-job mutex without the need for such a plethora
of mutexes.

Anthony

-- 
Author of C++ Concurrency in Action     http://www.stdthread.co.uk/book/
just::thread C++0x thread library             http://www.stdthread.co.uk
Just Software Solutions Ltd       http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk