Hello,
After some deep thought, I think I finally understand what the error
message "[BUG] cross-thread violation on rb_gc()" means. I will
present my understanding here; please correct me if I am wrong or
confirm if I am correct.
Suppose you have a C program which statically links with the Ruby
library and makes use of Ruby's C API functions. In particular, the
C program creates some Ruby strings from C strings using
StringValueCStr() and puts them inside a Ruby array.
So far so good. Now suppose that the C program wants to run an
embedded Ruby interpreter in the "background" while it is doing
other things. The C program does this by wrapping the ruby_run()
function (which never returns) inside a pthread.
Let's review the situation so far with a diagram:
{a process:
main()
{a pthread:
ruby_run()
}
}
Here we have the C program's main() function running in the
foreground and the embedded Ruby interpreter running in the background.
Now, suppose the embedded Ruby interpreter inside ruby_run() invokes
the garbage collector by calling the rb_gc() function. What happens?
There are two situations:
1. The garbage collector collects garbage created *only* by the
embedded Ruby interpreter inside ruby_run(). It ignores the garbage
created by the C program (remember that it created a Ruby array of
Ruby strings).
No problem here. The garbage collector frees up space for the
embedded Ruby interpreter and the interpreter merrily resumes
whatever it was doing.
2. The garbage collector tries to collect the Ruby array of Ruby
strings created by the C program. But wait a minute... the C program
which created that garbage is running in a *different* thread than
the embedded Ruby interpreter inside ruby_run()!
So, the garbage collector emits this error message and terminates
the Ruby interpreter (ruby_run): "[BUG] cross-thread violation on
rb_gc()".
That's my understanding of the error message. If I am correct, then
a solution to this problem would be to prohibit the C program from
using Ruby's C API functions. That way, the C program never creates
any Ruby objects which can be garbage collected by the embedded Ruby
interpreter that runs inside another thread.
What do you think?