# Understanding "cross-thread violation on rb\_gc()"

**URL:** <https://www.ruby-forum.com/t/understanding-cross-thread-violation-on-rb-gc/57912>\
**Category:** Ruby\
**Created:** [April 16, 2006, 3:54am UTC](https://www.ruby-forum.com/t/understanding-cross-thread-violation-on-rb-gc/57912 "2006-04-16T03:54:26Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Suraj\_NSKurapati](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3be4f8/32.png) [@Suraj\_NSKurapati](https://www.ruby-forum.com/u/Suraj_NSKurapati)\
**Post date:** [April 16, 2006, 3:54am UTC](https://www.ruby-forum.com/t/understanding-cross-thread-violation-on-rb-gc/57912/1 "2006-04-16T03:54:26Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

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.

1. 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?  
-----BEGIN PGP SIGNATURE-----  
Version: GnuPG v1.4.2.2 (GNU/Linux)

iD8DBQFEQaNpmV9O7RYnKMcRAsbjAKCYC8Ol/Gbs0zwHDHeOAnfdKVA6pwCePrxj  
7hSriKRe7Ih9cLODS+S6aSs=  
=Ys8a  
-----END PGP SIGNATURE-----

---

<div class="post-metadata">

**Author:** ![Suraj\_NSKurapati](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3be4f8/32.png) [@Suraj\_NSKurapati](https://www.ruby-forum.com/u/Suraj_NSKurapati)\
**Post date:** [April 16, 2006, 4:00am UTC](https://www.ruby-forum.com/t/understanding-cross-thread-violation-on-rb-gc/57912/2 "2006-04-16T04:00:28Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

Suraj N. Kurapati wrote:

> In particular, the  
> C program creates some Ruby strings from C strings using  
> StringValueCStr() and puts them inside a Ruby array.

Whoops, my mistake. The C program creates Ruby strings from C  
strings using rb\_str\_new2(), not by using StringValueCStr().

> Ruby strings).
> 
> What do you think?  
> -----BEGIN PGP SIGNATURE-----  
> Version: GnuPG v1.4.2.2 (GNU/Linux)

iD8DBQFEQaSmmV9O7RYnKMcRAuJ+AJwJrd6NLDb/a0MUSVUytLS4KZowCQCfW+e5  
FAa6ezQKcg2pv9KrEhw94rU=  
=8wBQ  
-----END PGP SIGNATURE-----

---

<div class="post-metadata">

**Author:** ![Suraj\_NSKurapati](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3be4f8/32.png) [@Suraj\_NSKurapati](https://www.ruby-forum.com/u/Suraj_NSKurapati)\
**Post date:** [April 16, 2006, 8:35am UTC](https://www.ruby-forum.com/t/understanding-cross-thread-violation-on-rb-gc/57912/3 "2006-04-16T08:35:00Z")

</div>

Hi,

At Sun, 16 Apr 2006 10:52:55 +0900,  
Suraj N. Kurapati wrote in [ruby-talk:188996]:

> 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 differences between objects created inside ruby\_run() and  
others. The ruby interpreter which is consisted from the core  
and many class libraries use each other, is also just one of  
programs using “embedded” interpreter.

> 1. 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()!

The point is where the object is stored.

Ruby GC scans the current machine stack to detect live objects,  
from the bottom of it through the current top of it. Note that  
the bottom is initialized the position of the stack when  
ruby\_init() is called. If you run it from another native  
thread other than the initial thread, the stack pointer will  
point another stack, and GC will run out “gaps” between those  
stacks.

> 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.

Incorrect.

You have to ensure rb\_gc() will run only in the initial thread,  
and all objects created in your program will be refered from  
somewhere other than the main stack.

---

<div class="post-metadata">

**Author:** ![Suraj\_NSKurapati](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3be4f8/32.png) [@Suraj\_NSKurapati](https://www.ruby-forum.com/u/Suraj_NSKurapati)\
**Post date:** [April 16, 2006, 10:44pm UTC](https://www.ruby-forum.com/t/understanding-cross-thread-violation-on-rb-gc/57912/4 "2006-04-16T22:44:13Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

Hi,

removed\_email\_address@domain.invalid wrote:

> Ruby GC scans the current machine stack to detect live objects,  
> from the bottom of it through the current top of it. Note that  
> the bottom is initialized the position of the stack when  
> ruby\_init() is called. If you run it from another native  
> thread other than the initial thread, the stack pointer will  
> point another stack, and GC will run out “gaps” between those  
> stacks.

Ah! Now I see. Thank you. 🙂

> somewhere other than the main stack.  
> Could you suggest a way to do this?

I hoped that after ruby\_init() was called, all new Ruby objects  
would automatically use the stack pointer prepared by ruby\_init().  
Unfortunately, that was not so:

I tried the following scenario where the C process (1) creates and  
runs the Ruby pthread, and (2) creates a Ruby array. But when the C  
process creates the Ruby array, the cross-thread violation occurs.  
Meaning that new Ruby objects are always created with respect to the  
stack pointer of the current thread/process, not with respect to the  
stack pointer prepared by ruby\_init().

{process:  
pthread\_create();  
…

```
{pthread:
	ruby_init();
	...
	ruby_run();
}

...
rb_ary_new(); // causes cross-thread violation on rb_gc()

```

}

At present, the only solution I know is to prohibit the C process  
from creating Ruby objects. Is there a way that the C process can  
create and use Ruby objects with respect to the stack pointer  
prepared by ruby\_init()?

Thanks.  
-----BEGIN PGP SIGNATURE-----  
Version: GnuPG v1.4.2.2 (GNU/Linux)

iD8DBQFEQqvfmV9O7RYnKMcRAgTmAKCCLo1MU8T15FEgWcH0XYb4NLu3rQCdHJSa  
EpZ1vrFIGmmmFnjzX69zIeg=  
=+x2Y  
-----END PGP SIGNATURE-----

---

<div class="post-metadata">

**Author:** ![Suraj\_NSKurapati](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3be4f8/32.png) [@Suraj\_NSKurapati](https://www.ruby-forum.com/u/Suraj_NSKurapati)\
**Post date:** [April 17, 2006, 1:42am UTC](https://www.ruby-forum.com/t/understanding-cross-thread-violation-on-rb-gc/57912/5 "2006-04-17T01:42:31Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

Suraj N. Kurapati wrote:

> …  
> rb\_ary\_new(); // causes cross-thread violation on rb\_gc()  
> }

Attached with this e-mail is example code for the above scenario. If  
you un-comment the function-call to rb\_ary\_new() inside main(), then  
the cross-thread violation does not occur.

Here is what happens when the scenario is compiled and run:

$ gcc -Wall -g -I$(ruby -rmkmf -e ‘puts $topdir’) \

- -l$(ruby -rmkmf -e ‘puts CONFIG[“RUBY\_SO\_NAME”]’) \
- -lpthread ctviol.c -o ctviol

$ ./ctviol  
[BUG] cross-thread violation on rb\_gc()  
ruby 1.8.4 (2005-12-24) [i486-linux]

Aborted (core dumped)

Here is the environment in which I ran the scenario:

$ ruby -v  
ruby 1.8.4 (2005-12-24) [i486-linux]

$ uname -a  
Linux yantram 2.6.15-20-386 #1 PREEMPT Tue Apr 4 17:48:51 UTC 2006  
i686 GNU/Linux

$ ulimit -a  
core file size (blocks, -c) unlimited  
data seg size (kbytes, -d) unlimited  
max nice (-e) unlimited  
file size (blocks, -f) unlimited  
pending signals (-i) unlimited  
max locked memory (kbytes, -l) unlimited  
max memory size (kbytes, -m) unlimited  
open files (-n) 1024  
pipe size (512 bytes, -p) 8  
POSIX message queues (bytes, -q) unlimited  
max rt priority (-r) unlimited  
stack size (kbytes, -s) 8192  
cpu time (seconds, -t) unlimited  
max user processes (-u) unlimited  
virtual memory (kbytes, -v) unlimited  
file locks (-x) unlimited

Thanks for your consideration.  
-----BEGIN PGP SIGNATURE-----  
Version: GnuPG v1.4.2.2 (GNU/Linux)

iD8DBQFEQtXbmV9O7RYnKMcRApdxAJ47u24c1Y9pUNmmGhDQY1sXpVmjoQCgjdo7  
QksRFhYmPV1Qb2b6/TDyHaw=  
=SIFP  
-----END PGP SIGNATURE-----

---

<div class="post-metadata">

**Author:** ![Suraj\_NSKurapati](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3be4f8/32.png) [@Suraj\_NSKurapati](https://www.ruby-forum.com/u/Suraj_NSKurapati)\
**Post date:** [April 17, 2006, 6:14am UTC](https://www.ruby-forum.com/t/understanding-cross-thread-violation-on-rb-gc/57912/6 "2006-04-17T06:14:32Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

Suraj N. Kurapati wrote:

> I applied this same technique to the previous example code (with  
> Ruby interpreter inside a pthread. As expected, the cross-thread  
> violation did not occur:

Unfortunately, this approach doesn’t work for a larger program where  
the Ruby thread creates so many Ruby objects that the garbage  
collector is invoked—at which point the cross-thread violation occurs.

> 1. Is the Ruby “environment” running inside ruby\_run\_handshake()  
> different from the Ruby “environment” running inside main()?

- From what I have observed, no.

> 1. If we create some Ruby arrays inside main(), will they be garbage  
> collected by the Ruby “environment” inside the pthread? vice versa?

- From what I have observed, yes.  
-----BEGIN PGP SIGNATURE-----  
Version: GnuPG v1.4.2.2 (GNU/Linux)

iD8DBQFEQxXTmV9O7RYnKMcRAjkmAKCLF5QU5Cr8z1cu/+YQxaeaThNDMwCeL/kq  
BKkngBWON0GNzRYv19s3twY=  
=DCO+  
-----END PGP SIGNATURE-----

---

<div class="post-metadata">

**Author:** ![Suraj\_NSKurapati](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3be4f8/32.png) [@Suraj\_NSKurapati](https://www.ruby-forum.com/u/Suraj_NSKurapati)\
**Post date:** [April 17, 2006, 7:46pm UTC](https://www.ruby-forum.com/t/understanding-cross-thread-violation-on-rb-gc/57912/7 "2006-04-17T19:46:42Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

removed\_email\_address@domain.invalid wrote:

> somewhere other than the main stack.  
> IMHO, the only practical to way to implement your suggestion is  
> through this policy:

1. Code executed by the C process _cannot_ use the Ruby C API.

2. Code executed by the Ruby thread _can_ use the Ruby C API.

At heart, this policy simply prohibits using the Ruby C API as a  
means of inter-process communication between the C process and the  
Ruby thread. Other means of inter-process communication, such as  
pipes or sockets, can be used instead.

Thus, the resulting scenario looks like this:

{process:  
// _never_ use the Ruby C API here

```
pthread_create();
...

{pthread:
	// use Ruby C API here

	ruby_init();
	...
	ruby_run();
}

...

```

}

Thanks for your advice and explanations.  
-----BEGIN PGP SIGNATURE-----  
Version: GnuPG v1.4.2.2 (GNU/Linux)

iD8DBQFEQ9QJmV9O7RYnKMcRAh1nAKCk0AN9fwYnkdwE8d4oSvtpokJ+7ACfXhqv  
MhSXxTGeUQXHH9Y/MM+cWdE=  
=ZbFX  
-----END PGP SIGNATURE-----

---

<div class="post-metadata">

**Author:** ![Suraj\_NSKurapati](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3be4f8/32.png) [@Suraj\_NSKurapati](https://www.ruby-forum.com/u/Suraj_NSKurapati)\
**Post date:** [April 17, 2006, 2:28am UTC](https://www.ruby-forum.com/t/understanding-cross-thread-violation-on-rb-gc/57912/8 "2006-04-17T02:28:17Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

Interestingly, the previous example code can be simplified into the  
following:

#include \<ruby.h\>

int main(int argc, char\*\* argv) {  
rb\_ary\_new(); // causes cross-thread violation on rb\_gc()

```
return 0;

```

}

Now the reason for the cross-thread violation is quite obvious: you  
cannot create Ruby objects without initializing the Ruby library  
first! So, a solution would look like this:

#include \<ruby.h\>

int main(int argc, char\*\* argv) {  
ruby\_init();  
rb\_ary\_new(); // no cross-thread violation!

```
return 0;

```

}

I applied this same technique to the previous example code (with  
Ruby interpreter inside a pthread. As expected, the cross-thread  
violation did not occur:

#include \<ruby.h\>  
#include \<pthread.h\>

void\* ruby\_run\_handshake(void\* dummy) {  
ruby\_init();  
ruby\_init\_loadpath();

```
ruby_run();	// this never returns

```

}

int main(int argc, char\*\* argv) {  
// run a Ruby interpreter in the background  
pthread\_t rubyThread;  
pthread\_create(&rubyThread, 0, ruby\_run\_handshake, 0);

```
// create some Ruby objects
ruby_init();
rb_ary_new();	// no cross-thread violation!

return 0;

```

}

Now, I have some questions regarding the above code:

1. Is the Ruby “environment” running inside ruby\_run\_handshake()  
different from the Ruby “environment” running inside main()?

2. Does ruby\_init() inside main() override the stack pointer  
prepared by ruby\_init() inside ruby\_run\_handshake()?

3. If we create some Ruby arrays inside main(), will they be garbage  
collected by the Ruby “environment” inside the pthread? vice versa?

Thanks for your attention.  
-----BEGIN PGP SIGNATURE-----  
Version: GnuPG v1.4.2.2 (GNU/Linux)

iD8DBQFEQuBUmV9O7RYnKMcRArTkAKCAf6YexFIZtbnH1Y4DWvQucPtWwACdGbQQ  
hgGSijw1DJTNnXolZGRuSrA=  
=VXYX  
-----END PGP SIGNATURE-----
