Thread overview | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
July 18, 2015 Sending an immutable object to a thread | ||||
---|---|---|---|---|
| ||||
Hey All, I'm trying to send immutable class objects to a thread, and am having trouble if the object is one of several variables sent to the thread. For example, I have a "Message" class: class Message { ... } and I create an immutable object from it, and send it to another thread: auto msg = immutable Message(...); Tid tid = spawn(&threadFunc); send(tid, thisTid(), msg); I then attempt to receive it in the threadFunc like: receive( (Tid cli, immutable Message msg) { int retCode = do_something_with(msg); send(cli, retCode); } ); I get compilation errors about the inability of building the tuple, like: /usr/include/dmd/phobos/std/variant.d(346): Error: cannot modify struct *zat Tuple!(Tid, immutable(Message)) with immutable members /usr/include/dmd/phobos/std/variant.d(657): Error: template instance std.variant.VariantN!32LU.VariantN.handler!(Tuple!(Tid, immutable(Message))) error instantiating /usr/include/dmd/phobos/std/variant.d(580): instantiated from here: opAssign!(Tuple!(Tid, immutable(Message))) /usr/include/dmd/phobos/std/concurrency.d(124): instantiated from here: __ctor!(Tuple!(Tid, immutable(Message))) /usr/include/dmd/phobos/std/concurrency.d(628): instantiated from here: __ctor!(Tid, immutable(Message)) /usr/include/dmd/phobos/std/concurrency.d(618): ... (1 instantiations, -v to show) ... /usr/include/dmd/phobos/std/concurrency.d(594): instantiated from here: _send!(Tid, immutable(Message)) MsgTest.d(92): instantiated from here: send!(Tid, immutable(Message)) I tried various combinations of using Rebindable, but couldn't get anything to compile. Thanks. |
July 18, 2015 Re: Sending an immutable object to a thread | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frank Pagliughi | OK, I found a couple of solutions, though if anyone can tell me something better, I would love to hear it. By making an alias to a rebindable reference, the receive() was able to create the tuple. So I renamed the class "MessageType": class MessageType { ... }; and then made a "Message" an immutable one of these: alias immutable(MessageType) Message; and finally made a "VarMessage" as a rebindable Message (thus, a mutable reference to an immutable object): alias Rebindable!(Message) VarMessage; [I will likely rethink these names, but anyway... ] Now I can send a reference to an immutable object across threads. The receiver wants the VarMessage: receive( (Tid cli, VarMessage msg) { int retVal = do_something_with(msg); send(cli, retVal); } ); and a few different things work to send the object: auto msg = new Message(...); send(tid, thisTid(), VarMessage(msg)); or: send(tid, thisTid(), rebindable(msg)); or: VarMessage vmsg = new Message(...); send(tid, thisTid(), vmsg); A second way that seems plausible is to just make the message a var type using a struct and then send a copy to the thread. This seems viable since the vast bulk of the message is a string payload, and thus the size of the struct is pretty small. |
July 19, 2015 Re: Sending an immutable object to a thread | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frank Pagliughi | It is a pitty that although Variant is the default message type in concurrency, it still has issues: https://issues.dlang.org/buglist.cgi?quicksearch=variant%20concurrency&list_id=202195 It looks like passing a pointer to an immutable(Message) works as well: import std.stdio; import std.concurrency; class Message { int i; this(int i) immutable { this.i = i; } } int do_something_with(immutable(Message) msg) { writefln("msg.i is %s", msg.i); return 0; } void threadFunc() { receive((Tid cli, immutable(Message) *msg) { int retCode = do_something_with(*msg); send(cli, retCode); }); ownerTid.send(42); } void main() { auto msg = new immutable(Message)(100); Tid tid = spawn(&threadFunc); send(tid, thisTid(), &msg); // <-- POINTER receiveOnly!int(); } Ali |
July 19, 2015 Re: Sending an immutable object to a thread | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | > It looks like passing a pointer to an immutable(Message) works as well:
Oh, yes, pointer. Ha! I didn't even think of that. Thanks.
I'm not familiar with how garbage collection works in D. If the initial reference goes out of scope, and you just have a pointer - in another thread, no less - then are you still guaranteed that the object will not disappear while the pointer exists?
Like if I did something akin to:
// ...like before...
void send_msg(Tid tid, int n)
{
auto msg = new immutable(Message)(n);
send(tid, thisTid(), &msg);
}
void main()
{
Tid tid = spawn(&threadFunc);
send_msg(tid, 100);
receiveOnly!int();
}
Do I know that the message object won't be garbage collected before the thread finishes with it? (I realize this is a very artificial example, but something like this could happen in a bigger library).
Frank
|
July 19, 2015 Re: Sending an immutable object to a thread | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frank Pagliughi | On Sunday, 19 July 2015 at 17:04:07 UTC, Frank Pagliughi wrote:
>> [...]
>
> Oh, yes, pointer. Ha! I didn't even think of that. Thanks.
>
> I'm not familiar with how garbage collection works in D. If the initial reference goes out of scope, and you just have a pointer - in another thread, no less - then are you still guaranteed that the object will not disappear while the pointer exists?
>
> [...]
a pointer to a pointer(or in this case, a reference) does not keep it alive.
|
July 21, 2015 Re: Sending an immutable object to a thread | ||||
---|---|---|---|---|
| ||||
Posted in reply to rsw0x | On Sunday, 19 July 2015 at 17:12:07 UTC, rsw0x wrote:
>
> a pointer to a pointer(or in this case, a reference) does not keep it alive.
Interesting. If you de-reference the pointer and assign it back, do you get back the keep-alive? Like, in the receiving thread:
void threadFunc()
{
receive((Tid cli, immutable(Message) *m) {
immutable(Message) msg = *m; // <---
int retCode = do_something_with(msg);
send(cli, retCode);
});
}
I assume that even if so, there is a race condition there. You would need to keep the original reference alive until at least the "msg = *m" assignment happened, right?
Or... could you tell the GC to leave the memory alone until the thread gets it? Like in the sending thread:
Tid tid = spawn(&threadFunc);
auto p = cast(void*) &msg;
GC.addRoot(p);
GC.setAttr(p, GC.BlkAttr.NO_MOVE);
send(tid, thisTid(), &msg);
//...
Is that possible? Is it efficient enough to do if you're sending lots and lots of messages?
Thanks.
|
July 21, 2015 Re: Sending an immutable object to a thread | ||||
---|---|---|---|---|
| ||||
Posted in reply to rsw0x | On Sunday, 19 July 2015 at 17:12:07 UTC, rsw0x wrote:
> On Sunday, 19 July 2015 at 17:04:07 UTC, Frank Pagliughi wrote:
>>> [...]
>>
>> Oh, yes, pointer. Ha! I didn't even think of that. Thanks.
>>
>> I'm not familiar with how garbage collection works in D. If the initial reference goes out of scope, and you just have a pointer - in another thread, no less - then are you still guaranteed that the object will not disappear while the pointer exists?
>>
>> [...]
>
> a pointer to a pointer(or in this case, a reference) does not keep it alive.
wow, I don't even remember posting this.
This is (mostly) wrong, but I'm unsure if a pointer to another pointer on the stack would correctly keep its object alive(but, I believe this would just be a bug I think,) If the pointer was pointing to a pointer on the heap, then AFAICT it would keep it alive.
|
July 21, 2015 Re: Sending an immutable object to a thread | ||||
---|---|---|---|---|
| ||||
Posted in reply to rsw0x | On Tuesday, 21 July 2015 at 21:44:07 UTC, rsw0x wrote: > On Sunday, 19 July 2015 at 17:12:07 UTC, rsw0x wrote: >> [...] > > wow, I don't even remember posting this. > > This is (mostly) wrong, but I'm unsure if a pointer to another pointer on the stack would correctly keep its object alive(but, I believe this would just be a bug I think,) If the pointer was pointing to a pointer on the heap, then AFAICT it would keep it alive. addendum: http://dlang.org/garbage.html >Pointers in D can be broadly divided into two categories: Those that point to garbage collected memory, and those that do not. Examples of the latter are pointers created by calls to C's malloc(), pointers received from C library routines, pointers to static data, pointers to objects on the stack, etc. >and those that do not ... pointers to objects on the stack, etc. I believe this implies that it would *not* keep the object alive. Sorry for the confusion/noise. |
July 22, 2015 Re: Sending an immutable object to a thread | ||||
---|---|---|---|---|
| ||||
Posted in reply to rsw0x | On Tuesday, 21 July 2015 at 21:50:35 UTC, rsw0x wrote:
> On Tuesday, 21 July 2015 at 21:44:07 UTC, rsw0x wrote:
>> On Sunday, 19 July 2015 at 17:12:07 UTC, rsw0x wrote:
>>> [...]
>>
>> wow, I don't even remember posting this.
>>
>> This is (mostly) wrong, but I'm unsure if a pointer to another pointer on the stack would correctly keep its object alive(but, I believe this would just be a bug I think,) If the pointer was pointing to a pointer on the heap, then AFAICT it would keep it alive.
>
> addendum:
> http://dlang.org/garbage.html
>
>>Pointers in D can be broadly divided into two categories: Those that point to garbage collected memory, and those that do not. Examples of the latter are pointers created by calls to C's malloc(), pointers received from C library routines, pointers to static data, pointers to objects on the stack, etc.
>
>>and those that do not ... pointers to objects on the stack, etc.
>
> I believe this implies that it would *not* keep the object alive.
>
> Sorry for the confusion/noise.
But as long as the original pointer is still on the stack, that one _will_ keep the object alive. It is only a problem if all pointers to a GC managed object are stored in places the GC isn't informed about.
|
July 22, 2015 Re: Sending an immutable object to a thread | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On Wednesday, 22 July 2015 at 09:04:49 UTC, Marc Schütz wrote:
> On Tuesday, 21 July 2015 at 21:50:35 UTC, rsw0x wrote:
>> On Tuesday, 21 July 2015 at 21:44:07 UTC, rsw0x wrote:
>>> [...]
>>
>> addendum:
>> http://dlang.org/garbage.html
>>
>>>[...]
>>
>>>[...]
>>
>> I believe this implies that it would *not* keep the object alive.
>>
>> Sorry for the confusion/noise.
>
> But as long as the original pointer is still on the stack, that one _will_ keep the object alive. It is only a problem if all pointers to a GC managed object are stored in places the GC isn't informed about.
correct, I managed to confuse myself :o)
|
Copyright © 1999-2021 by the D Language Foundation