View mode: basic / threaded / horizontal-split · Log in · Help
April 23, 2012
Issue calling methods using std.concurrency
Hello,

I'm getting some errors when I wrap a struct that I've written 
with another struct.  Here are the errors I'm getting:

tqueue.d(14): Error: function queue.Queue!(int).Queue.enqueue 
(int value) is not
 callable using argument types (int) shared
tqueue.d(15): Error: function queue.Queue!(int).Queue.dequeue () 
is not callable
 using argument types ()

Here's the receive block which the issue:

receive(
    (T value) { queue.enqueue(value); },
    (Tid caller) { send(caller, queue.dequeue); }
);

The queue itself is shared.  Outside of that, nothing special 
going on.  I just have a class that I want to be able to in a 
concurrent environment without having to modify the original 
class.

Any thoughts?
April 23, 2012
Re: Issue calling methods using std.concurrency
On 04/22/2012 07:15 PM, Casey wrote:
> Hello,
>
> I'm getting some errors when I wrap a struct that I've written with
> another struct. Here are the errors I'm getting:
>
> tqueue.d(14): Error: function queue.Queue!(int).Queue.enqueue (int
> value) is not
> callable using argument types (int) shared
> tqueue.d(15): Error: function queue.Queue!(int).Queue.dequeue () is not
> callable
> using argument types ()
>
> Here's the receive block which the issue:
>
> receive(
> (T value) { queue.enqueue(value); },
> (Tid caller) { send(caller, queue.dequeue); }
> );
>
> The queue itself is shared. Outside of that, nothing special going on. I
> just have a class that I want to be able to in a concurrent environment
> without having to modify the original class.
>
> Any thoughts?

This works at least with 2.059 on 64-bit Linux:

import std.stdio;
import std.concurrency;
import core.thread;

class Foo
{
    int i;
}

void workerFunc(Tid owner)
{
    receive(
        (shared(Foo) foo) {
            writeln("Before: ", foo.i);
            foo.i = 42;
        });

    owner.send(42);
}

void main (string[] args)
{
    shared foo = new shared(Foo);

    auto worker = spawn(&workerFunc, thisTid);
    worker.send(foo);
    receiveOnly!int();
    writeln("After: ", foo.i);
}

The output:

Before: 0
After: 42

Ali
April 23, 2012
Re: Issue calling methods using std.concurrency
On Monday, 23 April 2012 at 02:34:19 UTC, Ali Çehreli wrote:
> This works at least with 2.059 on 64-bit Linux:
>
> import std.stdio;
> import std.concurrency;
> import core.thread;
>
> class Foo
> {
>     int i;
> }
>
> void workerFunc(Tid owner)
> {
>     receive(
>         (shared(Foo) foo) {
>             writeln("Before: ", foo.i);
>             foo.i = 42;
>         });
>
>     owner.send(42);
> }
>
> void main (string[] args)
> {
>     shared foo = new shared(Foo);
>
>     auto worker = spawn(&workerFunc, thisTid);
>     worker.send(foo);
>     receiveOnly!int();
>     writeln("After: ", foo.i);
> }
>
> The output:
>
> Before: 0
> After: 42
>
> Ali

Ali,

I actually did print out the value being passed successfully.  
It's just that when I used the queue methods (enqueue and 
dequeue), it get this error.  The queue itself is shared, but 
none of the methods are expecting a shared value nor do I believe 
they should.

Casey
April 23, 2012
Re: Issue calling methods using std.concurrency
On 04/23/2012 11:44 AM, Casey wrote:

> I actually did print out the value being passed successfully. It's just
> that when I used the queue methods (enqueue and dequeue), it get this
> error. The queue itself is shared, but none of the methods are expecting
> a shared value nor do I believe they should.
>
> Casey

Could you please show a short program having the same problem. I am not 
familiar with enqueue or dequeue.

Ali
April 23, 2012
Re: Issue calling methods using std.concurrency
On Monday, 23 April 2012 at 18:44:37 UTC, Casey wrote:
>
> I actually did print out the value being passed successfully.  
> It's just that when I used the queue methods (enqueue and 
> dequeue), it get this error.  The queue itself is shared, but 
> none of the methods are expecting a shared value nor do I 
> believe they should.
>

From what I can gather from error messages, you have a shared 
reference to a non-shared class:

---

class Queue {
    void enqueue(int v) { /*...*/ }
    int dequeue() { /*...*/ }
}

// ...

auto queue = new shared(Queue);

// ...

---

If that is the case, then it's not that the methods are expecting 
a shared value, it's that methods are not 'expecting' a shared 
'this'. And indeed there is what seems to be a quirk in the 
design of 'shared' in that it won't allow such calls. But it is 
actually not a quirk, but means for the compiler to discard 
incorrect code. If you want your methods to be called for shared 
reference, the whole your class or at least those methods should 
be shared as well. Just like with const: if you have a const 
reference, you can only call const methods.

Whenever you encounter such issue, you should carefully think 
about what's going on. If the class you use is not designed to be 
shared, you shouldn't just start calling its methods from 
different threads, since it is by definition not safe, no matter 
what its documentation may state (remember, shared is there to 
enforce such guarantees). If it is actually made thread-safe 
(via, e.g. synchronized blocks), then the reference really 
shouldn't be shared.

All that said, your best bets are either to rethink your design 
(do you really need a shared queue if you are using message 
passing anyway?), or to provide an implementation for shared 
queue. If anything, consider that shared queue is very different 
from non-shared one: are you satisfied with locking queue, or do 
you need lockless one? Is your queue mostly read or written 
thread-wise, or maybe it's only one provider and one consumer? 
I'm sure experts in asynchronous programming can provide a dozen 
more questions that should be answered and then coded into the 
implementation of a queue that you want to share among threads.

I understand the desire to have one neat implementation that 
'just works', no matter the conditions, but unfortunately, with 
asynchronous programming that is not an option.
April 25, 2012
Re: Issue calling methods using std.concurrency
Stanislav: I think you just hit the nail on the head with the 
shared reference to this.  I didn't even think of that as the 
error message made me think of the parameter being shared.

As for solving it, I'll have to think about it.  I was hoping to 
just have a single queue class (Or any other in the future) that 
worked well single-threaded, but could be used in a 
multi-threaded environment if I used std.concurrency properly.  
Essentially, my goal was to have only a single queue, but use 
message passing to enqueue/dequeue items from the queue without 
having to create a custom thread-safe queue class.

Well, I guess I have to rethink what I'm doing.  Thanks!
Top | Discussion index | About this forum | D home