I want to move custom object to a thread (without channels by hand) I wrote this code
import locks
type
MyString = object
val: string
var L: Lock
proc `=destroy`(myStr: var MyString) =
echo "Destroy '", myStr, "' ", getThreadId()
`=destroy`(myStr.val)
var myThread: Thread[void]
var data {.guard: L.}: seq[MyString]
initLock(L)
proc printer() =
{.cast(gcsafe).}:
withLock L:
var theStr = data.pop()
echo "Printer: '", theStr.val, "' ", getThreadId()
echo "Main start: ", getThreadId()
var myStr = MyString(val: "Hello, World!")
withLock L:
data.add(myStr)
createThread(myThread, printer)
joinThread(myThread)
deinitLock(L)
echo "Main finish: ", getThreadId()
And the output is
Main start: 462466
Destroy '(val: "")' 462476
Printer: 'Hello, World!' 462476
Destroy '(val: "Hello, World!")' 462476
Main finish: 462466
Destroy '(val: "Hello, World!")' 462466
I have double destroy here. Why doesn't myStr moved (sinked) to seq ?
Or should I after adding to seq call wasMoved?
And what that empty Destroy '(val: "")' 462476 in thread?
Maybe you can show correct way to move value to thread?
These were tested on 1.6.0, unsure if the same will work on later versions.
The global context makes it so the destruction of myStr is delayed until program exit and var theStr = .. makes a copy instead. Wrapping it in a proc gives the result you expect.
import locks
type
MyString = object
val: string
proc `=destroy`(myStr: var MyString) =
echo "Destroy '", myStr, "' ", getThreadId()
`=destroy`(myStr.val)
var L: Lock
var data {.guard: L.}: seq[MyString]
proc main =
var myThread: Thread[void]
initLock(L)
proc printer() {.nimcall.} =
{.cast(gcsafe).}:
withLock L:
var theStr = data.pop()
echo "Printer: '", theStr.val, "' ", getThreadId()
echo "Main start: ", getThreadId()
var myStr = MyString(val: "Hello, World!")
withLock L:
data.add(myStr)
createThread(myThread, printer)
joinThread(myThread)
deinitLock(L)
echo "Main finish: ", getThreadId()
main()
You can make it gcsafe by passing a context object to the thread. This gives the same output somehow.
import locks
type
MyString = object
val: string
Context = ref object
L: Lock
data {.guard: L.}: seq[MyString]
proc `=destroy`(myStr: var MyString) =
echo "Destroy '", myStr, "' ", getThreadId()
`=destroy`(myStr.val)
proc main =
var myThread: Thread[Context]
var ctx = Context()
initLock(ctx.L)
proc printer(ctx: Context) {.nimcall.} =
withLock ctx.L:
var theStr = ctx.data.pop()
echo "Printer: '", theStr.val, "' ", getThreadId()
echo "Main start: ", getThreadId()
var myStr = MyString(val: "Hello, World!")
withLock ctx.L:
ctx.data.add(myStr)
createThread(myThread, printer, ctx)
joinThread(myThread)
deinitLock(ctx.L)
echo "Main finish: ", getThreadId()
main()