I wrote a test program that uses multiple sender and receiver threads that communicate via channels. The sender -> channel -> receiver chain is 1:1:1. However I want to store all threads and channels in tables, so that I can access any one of them by a key. This is to eventually build more complex code, where you can have more complex message flows.
Therefore I had to use ptrs for threads and channels. If the number of sender & receiver threads (and channels) is low, I don't hit an error easily. As soon as the count goes up exceptions start to happen. I've tested with ARC and ORC, which handle higher counts, but still see exceptions when the count is high enough (1,000 as in the uploaded example).
Here's the example code: https://gist.github.com/jfilby/23471abeefb382547736918b6d44d438
If anyone can tell me where I've gone wrong, please let me know. Thanks.
In your gist, you're not using the channel.lock itself. Try to lock/unlock (or acquire/release?) when reading or writing to channel.list.
You can also try separate lock for fetching and assigning the channel to the list, but using the same lock for fetching/assigning channel should be simpler.
Sorry, I run your example and it's immediately failing with this message:
D:\test.nim(203) receiver
Error: unhandled exception: Message received is invalid:
myMsg.str (This is a test for: 19) != "This is a test for: 27" [ValueError]
D:\test.nim(203) receiver
Error: unhandled exception: Message received is invalid:
myMsg.str (This is a test for: 29) != "This is a test for: 33" [ValueError]
So I thought this is the usual case of race-condition, the changes could be
withLock channel.lock:
(channels.list[uniqueStr],
senderThreads[uniqueStr]) =
addSenderThreadWithChannel(uniqueStr)
withLock channel.lock
receiverThreads[uniqueStr] =
addReceiverThreadWithChannel(
uniqueStr,
channels.list[uniqueStr])
but apparently it yielded the same. There should anywhere which make it race-condition but other than channel.list but I couldn't see it in others. Also running it simply with nim r --threads:on test.nim so maybe it could be different with -d:release .
I get an exception right at the start:
channels_test.nim(223) channels_test
channels_test.nim(116) concurrencyTests
channels_test.nim(50) addReceiverThreadWithChannel
SIGSEGV: Illegal storage access. (Attempt to read from nil?)