
{"id":4581,"date":"2019-10-26T00:21:20","date_gmt":"2019-10-26T04:21:20","guid":{"rendered":"https:\/\/ikriv.com\/blog\/?p=4581"},"modified":"2019-10-26T00:38:45","modified_gmt":"2019-10-26T04:38:45","slug":"c-why-ability-to-lock-on-any-object-was-a-bad-idea","status":"publish","type":"post","link":"https:\/\/ikriv.com\/blog\/?p=4581","title":{"rendered":"C#: why ability to lock on any object was a bad idea"},"content":{"rendered":"<p>Any programming language gives you plenty of opportunities to shoot yourself in the foot, and C# is probably not the worst, but I ran into an interesting example today.<\/p>\n<p>C# has built-in language support for exclusive locking via the <code>lock<\/code> keyword, but not for read\/write locking. Fortunately, .NET class library has <code>ReaderWriterLockSlim<\/code>, and with the help of some extension methods we can make the locks automatically releaseable upon exit from the code block.<\/p>\n<p>You use <code>lock<\/code> to lock built-in locks, and lock custom locks using <code>using<\/code> (pardon me the pun). For example:<\/p>\n<pre>var exclusiveLock = new object();\r\n<b>lock<\/b> (exclusiveLock) { \/* stuff *\/ }\r\n\r\n<span style=\"color: darkgreen;\">\/\/ ReaderWriterLockSlim.Write() is an extension method \r\n\/\/ It returns an auxilliary object that releases the lock when disposed<\/span>\r\nvar rwLock = new ReaderWriterLock();\r\n<b>using<\/b> (rwLock.Write()) { \/* more stuff *\/ } \r\n<\/pre>\n<p>This is bad, but not terrible. What <strong>is<\/strong> terrible is that the <code>lock<\/code> keyword works on <em>any<\/em> object, including the custom lock, but not the way you&#8217;d expect. In my case I converted from exclusive locks to R\/W locks, but forgot to change some <code>lock<\/code> keywords into <code>using<\/code>, so I ended up with something like this:<\/p>\n<pre>var rwLock = new ReaderWriterLockSlim();\r\n\r\n<b>lock<\/b> (rwLock.Write()) { \/* stuff *\/ }\r\n<b>using<\/b> (rwLock.Read()) { \/* more stuff *\/ }<\/pre>\n<p>This compiles just fine, but fails at runtime with an exception:<\/p>\n<p><code style=\"color: brown;\">Unhandled Exception: System.Threading.LockRecursionException: A read lock may not be acquired with the write lock held in this mode.<\/code><\/p>\n<p>What&#8217;s going on here and what does this mean? The write lock is acquired and never released. Then the code proceeds to acquire a read lock, and that (thankfully) fails. The exception message is not ideal, the cryptic &#8220;this mode&#8221; means &#8220;non-recursive locking mode&#8221;, which is the default for reader\/writer locks in .NET, but that problem is minor.<\/p>\n<p>The idea that any object can have an exclusive lock attached to it looks dubious, but benign. However, the corollary that a read\/write lock object can have an exclusive lock attach to it is outright bad. Objects are objects, and locks are locks, and converting any object into an exclusive lock does not do any good to anyone.<\/p>\n<p>The <code>lock<\/code> keyword should have been restricted only to actual locks, just like the <code>using<\/code> keyword is restricted to objects that implement <code>IDisposable<\/code>.<\/p>\n<p>What C# should have had but doesn&#8217;t, is built-in support for disposable reader\/writer locks. As a result, everyone seems to invent their own variation. <a href=\"https:\/\/gist.github.com\/ikriv\/c9a3018e98ecce3d1392c090ed54052d\">Mine is here<\/a>, loosely based on a StackOverflow article that I can&#8217;t easily find now, but I am still not claiming all the credit. You can find a couple of dozen more if you search the Internet, and this is not a good sign, such thing should be standard.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Any programming language gives you plenty of opportunities to shoot yourself in the foot, and C# is probably not the worst, but I ran into an interesting example today. C# <a href=\"https:\/\/ikriv.com\/blog\/?p=4581\" class=\"more-link\">[&hellip;]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"Layout":"","footnotes":""},"categories":[1],"tags":[],"class_list":["entry","author-ikriv","post-4581","post","type-post","status-publish","format-standard","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4581","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4581"}],"version-history":[{"count":5,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4581\/revisions"}],"predecessor-version":[{"id":4586,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4581\/revisions\/4586"}],"wp:attachment":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4581"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4581"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4581"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}