www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Can/should spawn work with functions that return?

reply Andrej Mitrovic <none none.none> writes:
import std.stdio;
import std.concurrency;

void foo(int var)
{
}

bool bar(int var)
{
    return true;
}

void barWrapper(int var)
{
    bar(var);
}

void main()
{
    spawn(&foo, 1);
    spawn(&barWrapper, 1);
    spawn(&bar, 1);
}

Errors:
testSpawn.d(24): Error: template std.concurrency.spawn(T...) does not match any
function template declaration
testSpawn.d(24): Error: template std.concurrency.spawn(T...) cannot deduce
template function from argument types !()(bool function(int var),int)

Of course, when my foreground thread spawns a background thread it doesn't wait
for it to finish, so assigning a return value doesn't make much sense. I can
see how that can be an error (in any case that error message above is not very
informative).

But what if I want to spawn a thread with an existing function 'bar' that has
side-effects, but I'm not interested in its return value even though it has
one? 

Right now I'm forced to either:
a) remove any returns from 'bar' and change it to a void function, which can be
really complicated if other functions already depend on its return value, or
b) write a new void function that can be called with spawn(), which internally
calls 'bar' but discards it's value (so basically it's a wrapper). This is what
I've done in the example code.

So, is spawning threads on functions that return banned by design? I couldn't
read about this anywhere on the D site or TDPL.
Jan 21 2011
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, January 21, 2011 14:12:18 Andrej Mitrovic wrote:
 import std.stdio;
 import std.concurrency;
 
 void foo(int var)
 {
 }
 
 bool bar(int var)
 {
     return true;
 }
 
 void barWrapper(int var)
 {
     bar(var);
 }
 
 void main()
 {
     spawn(&foo, 1);
     spawn(&barWrapper, 1);
     spawn(&bar, 1);
 }
 
 Errors:
 testSpawn.d(24): Error: template std.concurrency.spawn(T...) does not match
 any function template declaration testSpawn.d(24): Error: template
 std.concurrency.spawn(T...) cannot deduce template function from argument
 types !()(bool function(int var),int)
 
 Of course, when my foreground thread spawns a background thread it doesn't
 wait for it to finish, so assigning a return value doesn't make much
 sense. I can see how that can be an error (in any case that error message
 above is not very informative).
 
 But what if I want to spawn a thread with an existing function 'bar' that
 has side-effects, but I'm not interested in its return value even though
 it has one?
 
 Right now I'm forced to either:
 a) remove any returns from 'bar' and change it to a void function, which
 can be really complicated if other functions already depend on its return
 value, or b) write a new void function that can be called with spawn(),
 which internally calls 'bar' but discards it's value (so basically it's a
 wrapper). This is what I've done in the example code.
 
 So, is spawning threads on functions that return banned by design? I
 couldn't read about this anywhere on the D site or TDPL.

The current design does not give you any way to access a return value from a spawned function, even if it allowed you to use such a function. And given that fact, it really doesn't make sense conceptually to have spawn work with non-void functions. I'm not sure that there are any technical barriers to it however. Still, as it stands, if a function isn't _designed_ to be called with spawn, I don't see what good it generally does you. If it's not sending messages to the parent thread, then what's the point of calling it? You can't _have_ side effects unless the function alters a shared global. I do have an enhancement request related to getting return values from spawned functions though: http://d.puremagic.com/issues/show_bug.cgi?id=4566 - Jonathan M Davis
Jan 21 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Sorry, I should be careful with the word side-effects. What I meant
was the newly spawned thread does its own job that the main thread
doesn't care much about. It doesn't touch main's state or any shared
variables. It does some work other than return a value. But the
function I wanted the new thread to execute happened to have a return
value, so I couldn't spawn the thread.

Really, the issue is that sometimes I have to convert C code to D and
concurrency is dealt with differently in the two languages, not to
mention the fact that I have next to no experience with using threads
in any language (but I'm forced to use them in some cases).

So, sometimes I'll ask silly questions because I'm very new to this,
but hopefully I'll learn a thing or two. I do enjoy your long and
informative responses though, Jonathan. :)
Jan 21 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, January 21, 2011 15:23:37 Andrej Mitrovic wrote:
 Sorry, I should be careful with the word side-effects. What I meant
 was the newly spawned thread does its own job that the main thread
 doesn't care much about. It doesn't touch main's state or any shared
 variables. It does some work other than return a value. But the
 function I wanted the new thread to execute happened to have a return
 value, so I couldn't spawn the thread.
 
 Really, the issue is that sometimes I have to convert C code to D and
 concurrency is dealt with differently in the two languages, not to
 mention the fact that I have next to no experience with using threads
 in any language (but I'm forced to use them in some cases).
 
 So, sometimes I'll ask silly questions because I'm very new to this,
 but hopefully I'll learn a thing or two. I do enjoy your long and
 informative responses though, Jonathan. :)

Well, I'd suggest just wrapping the function call in a lambda, unless spawn doesn't like that for some reason. I suppose that spawn could be made take functions with return values, but it's not generally something that you'd do, and it _is_ pretty easy to wrap such functions, so it seems to me like it's probably better as it is - though I can see why it would be annoying if you kept needing to spawn functions with return values. Still, that makes me wonder about what you're doing. I guess that you could be doing I/O or somethnig, but you certainly can't be talking back to the parent thread without having written things that way (in which case, you'd have made the spawned function void). You could always put in an enhancement request, though it does seem wrong to me (conceptually-speaking, if nothing else) to have a spawned function with a return value. - Jonathan M Davis
Jan 21 2011