<div class="gmail_quote">On Wed, Jan 20, 2010 at 9:23 AM, Kevin Bealer <span dir="ltr"><<a href="mailto:kevinbealer@gmail.com">kevinbealer@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="PADDING-LEFT: 1ex; MARGIN: 0px 0px 0px 0.8ex; BORDER-LEFT: #ccc 1px solid">There is a type of locking pattern that solves this issue. It involves locks that can be in "read", "write" or "shared" mode. The concept is that you get a shared lock when you might want to upgrade to a write lock.<br>
<br>Shared mode can coexist with other threads that are in "read" mode, but is not compatible with other threads that are in write or shared mode. You can upgrade a shared mode lock to a write lock without deadlocking -- it waits for other threads to finish reading.<br>
<br>The normal usage pattern is that you get a shared mode when you might want to modify something. Let's say that a user wants to write a line to a logfile. You get a shared mode lock on the directory, then check if the file exists. If it already exists, you downgrade the shared lock to a read lock, then get a write mode lock on the file. If the file does not exist, you instead upgrade the shared lock to a write lock, then create the file (which is why you needed write permissions), then get a write lock on the new file and downgrade or release the directory lock.<br>
<br>This model of locking cannot deadlock on itself because there is only one "shared" process at a time -- when getting a shared lock, you need to wait for all existing writers to exit, and for any existing shared lock holders to exit or downgrade. It works best for cases where a processes often thinks it *might* need to do a write operation but usually doesn't, in which case it reduces lock contention for reader threads. The most common situation is where you don't know if you need to do the write until you've done some reads to asses the current situation.<br>
<br>I know we used locks like this when I was at IBM. I wish I could find out who invented this so I know whether it is patented. (IBM loves patents -- I suspect it isn't patented but I haven't found a good writeup of it online yet.)<br>
<font color="#888888"><br>Kevin</font>
<div>
<div></div>
<div class="h5"> </div></div></blockquote>
<div> </div>
<div>Never mind that last bit, I just noticed that read/write/shared locks as I describe here are available in boost. The patent I remember had something to do with specifics of how it was implemented.</div>
<div> </div>
<div>Kevin<br></div>
<blockquote class="gmail_quote" style="PADDING-LEFT: 1ex; MARGIN: 0px 0px 0px 0.8ex; BORDER-LEFT: #ccc 1px solid">
<div>
<div class="h5">
<div class="gmail_quote">On Wed, Jan 20, 2010 at 7:28 AM, Michel Fortin <span dir="ltr"><<a href="mailto:michel.fortin@michelf.com" target="_blank">michel.fortin@michelf.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="PADDING-LEFT: 1ex; MARGIN: 0pt 0pt 0pt 0.8ex; BORDER-LEFT: rgb(204,204,204) 1px solid">Le 2010-01-20 à 2:07, Sean Kelly a écrit :<br>
<div><br>> Is what you want in core.sync.rwmutex? You can use it as:<br>><br>> synchronized( mut.reader ) {}<br>> synchronized( mut.writer ) {}<br>><br>> It doesn't currently allow upgrading read locks to write locks, though I think this wouldn't be difficult to add. More importantly I suppose is that acquiring a concurrent read lock may be more expensive than you'd expect, so you really only want to use a ReadWriteMutex if the read operations take a reasonable amount of time to complete.<br>
<br></div>What happens if you call test() here?<br><br> void test() {<br> synchronized (mut.reader) {<br> // read A<br> testWrite();<br> // read B<br>
}<br> }<br><br> void testWrite() {<br> syncrhonized (mut.writer) {<br> // write C<br> }<br> }<br><br>I guess that if you haven't implemented upgrades this will deadlock.<br>
<br>I'd like to note that even upgrading the lock to a write lock might be a problem: as I said in my other message, making this an automatic upgrade might force the release the reader lock until the writer lock is acquired, which would be unexpected from test()'s point of view.<br>
<br>This could work well as a transaction, where a failure to upgrade the lock would throw an exception, "read A" would be rollbacked, and the synchronized part would be attempted again. But without proper logic to deal with the unfortunate case of a failed upgrade you have either a race or a deadlock here.<br>
<div><br>--<br>Michel Fortin<br><a href="mailto:michel.fortin@michelf.com" target="_blank">michel.fortin@michelf.com</a><br><a href="http://michelf.com/" target="_blank">http://michelf.com/</a><br><br><br><br>_______________________________________________<br>
</div>
<div>
<div></div>
<div>dmd-concurrency mailing list<br><a href="mailto:dmd-concurrency@puremagic.com" target="_blank">dmd-concurrency@puremagic.com</a><br><a href="http://lists.puremagic.com/mailman/listinfo/dmd-concurrency" target="_blank">http://lists.puremagic.com/mailman/listinfo/dmd-concurrency</a><br>
</div></div></blockquote></div><br></div></div></blockquote></div><br>