import threadpool
type
AbcImpl = object of RootObj
a* : int
b* : float
c* : string
DefImpl = object of RootObj
d* : string
e* : float
f* : float
g* : int
Abc* = ref AbcImpl
Def* = ref DefImpl
var channel:Channel[tuple[t:string,data:ref RootObj]]
proc recieveMsg() =
let (avai,msg) = channel.tryRecv()
echo repr msg
if avai :
let (t,data) = msg
case t
of "Abc":
echo "Abc\n", repr(data)
of "Def":
echo "Def\n", repr(data)
else:
echo "else\n", repr(data)
proc sendMsg() =
var abc = new(Abc)
abc.a = 1
abc.b = 2.0
abc.c = "cccc"
channel.send((t:"Abc",data:abc))
proc main() =
channel.open()
spawn sendMsg()
spawn recieveMsg()
sync()
channel.close()
main()
In this example, It could not recieve any useful data. [Field0 = 000000000077D0A0"Abc", Field1 = ref 000000000077E050 --> []]
Abc ref 000000000077E050 --> [] so I modified it like this:
var channel:Channel[tuple[t:string,data:ptr RootObj]]
proc sendMsg() =
var abc = new(Abc)
abc.a = 1
abc.b = 2.0
abc.c = "cccc"
channel.send((t:"Abc",data:cast[ptr RootObj](abc)))
I got the data. Abc ref 000000000076C050 --> [a = 1, b = 2.0, c = 000000000076D050"cccc"]
But I don't know do it like this is GC safe ? And Is "Abc" data in the revieve proc safe ?
Yes, channels work with ref objects (they will be copied). Your problem is that you are using tryRecv, and the message has not yet arrived by the time you call tryRecv. If you use recv (or put the tryRecv call in a loop [1]), it works.
[1] Note that using tryRecv in a loop is generally not a great idea unless you know what you are doing.
I played with that too. First I did was putting the tryRecv into a loop and it still did not work for the data but only for the t which was "Abc" but data was still []. It works when casted to the ptr. What I did not understand was why the string works (and has a different memory address when checked from inside the thread than from the outside).
See:
import threadpool, os
type
AbcImpl = object of RootObj
a* : int
b* : float
c* : string
DefImpl = object of RootObj
d* : string
e* : float
f* : float
g* : int
Abc* = ref AbcImpl
Def* = ref DefImpl
var channel:Channel[tuple[t:string,data:ptr RootObj]]
proc recieveMsg() =
var wait = true
while wait:
let (avai,msg) = channel.tryRecv()
if avai:
wait = false
let (t,data) = msg
echo repr t
case t
of "Abc":
echo "Abc\n", repr(data)
of "Def":
echo "Def\n", repr(data)
else:
echo "else\n", repr(data)
sleep(100)
proc sendMsg() =
var abc = new(Abc)
abc.a = 1
abc.b = 2.0
abc.c = "cccc"
var msg = (t:"Abc",data:cast[ptr RootObj](abc))
echo repr msg.t
channel.send(msg)
sleep(1000)
echo repr(abc)
echo "done"
proc main() =
channel.open()
spawn sendMsg()
spawn recieveMsg()
sync()
channel.close()
main()
The other problem is that the type is specified as ref RootObj. Sending data across a channel is based on the declared type, not the dynamic type.
Using ptr is a bad idea unless you know what you are doing, because the garbage collector may reclaim the object before it's being used in the other thread. It will also break if the object contains other GC-ed data (such as strings).
var channel:Channel[tuple[t:string, data:RootObj]]
proc sendMsg() =
var abc = new(Abc)
abc.a = 1
abc.b = 2.0
abc.c = "cccc"
channel.send((t:"Abc", data:cast[RootObj](abc[])))
But I can't compile it. So, I hope that there is a proc like send(pData:pointer, size:int) as this proc of socket.
e2718e: But I can't compile it.
A few notes: