www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to use containers in lock based concurrency

reply ANtlord <antlord92 gmail.com> writes:
Hello! I can't get how to use double linked list in concurrency. 
Please help.

Providing code


import std.stdio;
import std.container;


synchronized class SocksQueue {
     private shared(DList!string) _queue;
     public void f(string data) {
         this._queue.insertFront(data);
     }
}

void main(string[] args)
{
}

I get a compile error onlineapp.d(8): Error: template 
std.container.dlist.DList!string.DList.insertFront cannot deduce 
function from argument types !()(string) shared, candidates are:
/dlang/dmd/linux/bin64/../../src/phobos/std/container/dlist.d(441):       
std.container.dlist.DList!string.DList.insertFront(Stuff)(Stuff stuff)

https://run.dlang.io/gist/3afff560fe3b2f439272c3ee3adcebd0?compiler=dmd
Nov 03
parent reply crimaniak <crimaniak gmail.com> writes:
On Friday, 3 November 2017 at 12:42:29 UTC, ANtlord wrote:
 Hello! I can't get how to use double linked list in 
 concurrency. Please help.
...
 I get a compile error onlineapp.d(8): Error: template 
 std.container.dlist.DList!string.DList.insertFront cannot 
 deduce function from argument types !()(string) shared,
One Does Not Simply get the non-shared object and use in the shared code. (/Boromir mode) For me, it was useful to read this: http://www.informit.com/articles/article.aspx?p=1609144&seqNum=11
Nov 03
parent reply Nathan S. <no.public.email example.com> writes:
Is this advice from 2015 outdated? I found it while I was 
wrestling with shared data structures, and after reading I 
stopped doing that.

https://p0nce.github.io/d-idioms/#The-truth-about-shared

The truth about shared
It's unclear when and how shared will be implemented.
Virtually noone use shared currently. You are better off 
ignoring it at this moment.
Nov 03
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, November 03, 2017 21:23:02 Nathan S. via Digitalmars-d-learn 
wrote:
 Is this advice from 2015 outdated? I found it while I was
 wrestling with shared data structures, and after reading I
 stopped doing that.

 https://p0nce.github.io/d-idioms/#The-truth-about-shared

The truth about shared
It's unclear when and how shared will be implemented.
Virtually noone use shared currently. You are better off
ignoring it at this moment.
That advice was wrong when it was written. Plenty of folks don't understand how to use shared properly, and there are lots of folks who cop out and use __gshared instead, but shared _does_ work, even if it's annoying to use, and __gshared is only intended for C globals. Using it on D objects is just begging for problems, because the type system will treat them as thread-local even though they're not. So, using __gshared can lead to subtle, hard-to-find bugs that shared code won't have. One of the problems with shared has been that it hasn't been used where it should be (e.g. core.sync.mutex didn't use it, but I think that that's been fixed now), making it harder to write shared code than it should be. However, a lot of it just comes down to the fact that everyone balks at the fact that shared requires casting to use properly. You rarely simply call functions on shared objects, because if you did, there would be race conditions. Rather, the way that shared should normally be used is essentially: shared(MyObject) mySharedObject; // ... synchronized(mutexForMySharedObject) { auto myObj = cast(MyObject)mySharedObject; // do stuff with myObj // ... // make sure that at this point, there are no thread-local references // to mySharedObject which have escaped. } // And here, after the lock is released, we should just have the shared // reference again. It would be nice if we had a way to use shared that didn't require explicit casting like that, but that code is essentially would you would do in a C++ program that was correctly dealing with objects shared across threads except that the C++ program wouldn't have to cast away shared, because it puts everything in shared memory whether it's actually used on multiple threads or not, and its type system doesn't help you segregate code that operates on objects that are used across threads. The annoyances with D's shared come from it preventing you from doing stuff that actually isn't thread-safe and requiring you to go to extra effort to then use the objects. What we end up with is a bit like safe and trusted in that most of the code does not use shared objects and has any shared objects that it does have explicitly marked that way, and then there are small sections of code where you do the risky thing that requires scrutiny where you cast away shared and operate on it as if it were thread-local - of course, with a lock to ensure that it's actually safe to operate on the object as thread-local, but all of that requires that the programmer manually verify it rather than the compiler being able to guarantee it for you like it can be preventing you from doing stuff with shared objects that isn't thread-safe. In principle, synchronized classes as described in TDPL are supposed to at least partially solve the casting problem, because they would guarantee that the objects don't escape from the synchronized class, allowing the compiler to safely remove the outer layer of shared on member variables so that you get that automatic cast - but only for the outer layer of shared (since they can't guarantee that no other references to the data exist beyond the outer layer). So, synchronized classes would only partially solve the problem. But regardless, we don't actually have synchronized classes at the moment - just synchronized functions - so we don't get even that much right now. There is occasionally talk about overhauling shared in order to improve it, but I think that most of that has to do with better defining spec-wise what's going on with the memory model. We may very well be able improve some of how shared is used as well, but fundamentally, it's very difficult to guarantee that no other references could be mucking around with an object in a given piece of code such that the compiler can automatically cast away shared for you. As with trusted, it requires the programmer to do the right thing and verify that they're doing the right thing. - Jonathan M Davis
Nov 03