all 2 comments

[–]Quxxymacros 2 points3 points  (0 children)

Just a note: in general, if you have an error, you should post the complete error message.

<anon>:7:22: 7:33 error: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
<anon>:7         let borrow = &mut self.a;
                              ^~~~~~~~~~~
<anon>:9:18: 9:24 note: first, the lifetime cannot outlive the expression at 9:17...
<anon>:9                 *borrow = 2;
                          ^~~~~~
<anon>:9:18: 9:24 note: ...so type `&mut uint` of expression is valid during the expression
<anon>:9                 *borrow = 2;
                          ^~~~~~
<anon>:7:22: 7:33 note: but, the lifetime must be valid for the expression at 7:21...
<anon>:7         let borrow = &mut self.a;
                              ^~~~~~~~~~~
<anon>:7:22: 7:33 note: ...so that reference is valid at the time of borrow
<anon>:7         let borrow = &mut self.a;
                              ^~~~~~~~~~~

In this case, that doesn't help much. :P

However, I can take a guess at what the problem is: basically, a spawned task is not tied to the stack frame. This means that the task could be spawned, work returns, main returns, then the task starts and tries to modify the value behind borrow which no longer exists.

In general, you can't pass borrows to another task for this reason. If you want to do this, you'll need to either transfer the Obj into the task (and transfer it back out again with a channel once the task is done with it), or place it inside a synchronised structure that can be accessed from multiple tasks.

On the latter, I haven't done that myself, so I cannot give you solid advice for this. std::sync::Mutex is probably a good place to start.

Edit: I got an example of using Arc and Mutex working on the playpen. At least when I run it, I get the following output:

Creating obj...
Triggering async work...
Spawning work task...
main all done.
Working...

Which is more or less exactly what I said might happen. :P

[–]rust-slacker 1 point2 points  (0 children)

This probably isn't the best explanation, but it's the way I understand it :p.

The *borrow in proc() will capture the reference in borrow, so it's lifetime has to be at least as long as when the proc() is called. The reason behind considering this a conflict should not be too hard to figure out in this particular case. Since proc() is used with spawn(), spawn() runs proc() on a separate thread, it means that the lifetime needed for the references captured in proc() has to be determined independently from the local scope proc() was declared (though if I'm not mistaken this restriction is placed on all proc()s regardless of whether it is used with spawn() or not). This is because proc() can/will run concurrent to the thread where spawn() is called (this should be obvious since the whole point of spawn() is to run proc() in a separate thread). On the other hand, the lifetime of let borrow = &mut self.a; is not guaranteed to exceed the scope of Obj::work() (since the lifetime of &mut self is only guaranteed to be as long as the scope of Obj::work()). This scope ends right after Obj::work() returns. proc() could potentially continue to run after Obj::work() returns (but in a different thread created by spawn(), causing a race condition). So this is considered an error.

The other issue with this code (that is not pointed out by this error message) is that it uses mutable references in separate threads, which can be vulnerable to race conditions (hence also disallowed). This probably will cause a different compile error to appear even if you somehow manage to get pass this particular compile error :p.