44883

calling IO Operations from thread in ruby c extension will cause ruby to hang

Question:

I have a problem with using threads in a C Extension to run ruby code async.

I have the following C code:

struct DATA { VALUE callback; pthread_t watchThread; void *ptr; }; void *executer(void *ptr) { struct DATA *data = (struct DATA *) ptr; char oldVal[20] = "1"; char newVal[20] = "1"; pthread_cleanup_push(&threadGarbageCollector, data); while(1) { if(triggerReceived) { rb_funcall(data->callback, rb_intern("call"), 0); } } pthread_cleanup_pop(1); return NULL; } VALUE spawn_thread(VALUE self) { VALUE block; struct DATA *data; Data_Get_Struct(self, struct DATA, data); block = rb_block_proc(); data->callback = block; pthread_create(&data->watchThread, NULL, &executer, data); return self; }

I am using this because I want to provide ruby-code as a callback, which will be executed, once the Thread receives a signal.

In general this is working fine, if the callback is something like this ruby-code:

1 + 1

But, if the callbacks ruby-code looks like this:

puts "test"

than the main ruby process will stop responding, once the callback is getting executed. The thread is still running and able to react to signals and puts the "test" everytime, the thread receives a message.

Can somebody maybe tell me, how to fix this?

Thanks a lot

Answer1:

<a href="https://docs.ruby-lang.org/en/trunk/extension_rdoc.html#label-Threading" rel="nofollow">From the Ruby C API docs</a>:

<blockquote>

As of Ruby 1.9, Ruby supports native 1:1 threading with one kernel thread per Ruby Thread object. Currently, there is a GVL (Global VM Lock) which prevents simultaneous execution of Ruby code which may be released by the rb_thread_call_without_gvl and rb_thread_call_without_gvl2 functions. These functions are tricky-to-use and documented in thread.c; do not use them before reading comments in thread.c.

</blockquote>

TLDR; the Ruby VM is not currently (at the time of writing) thread safe. Check out <a href="https://silverhammermba.github.io/emberb/c/#threading" rel="nofollow">this nice write-up on Ruby Threading</a> for a better overall understanding of how to work within these confines.

You can use Ruby's <a href="https://github.com/ruby/ruby/blob/ruby_2_5/thread_pthread.c#L986" rel="nofollow">native_thread_create(rb_thread_t *th)</a> which will use pthread_create behind the scenes. There are some drawbacks that you can read about in the documentation above the method definition. You can then run your callback with Ruby's <a href="https://github.com/ruby/ruby/blob/ruby_2_5/thread.c#L1531" rel="nofollow">rb_thread_call_with_gvl</a> method. Also, I haven't done it here, but it might be a good idea to create a wrapper method so you can use rb_protect to handle exceptions your callback may raise (otherwise they will be swallowed by the VM).

VALUE execute_callback(VALUE callback) { return rb_funcall(callback, rb_intern("call"), 0); } // execute your callback when the thread receives signal rb_thread_call_with_gvl(execute_callback, data->callback);

Recommend

  • Streaming bytes via HTTP PUT with JAX-RS
  • Way to draw NSString on a curved path?
  • libgit2 with libssh2 and libopenssl on windows
  • Select with two counts on same column
  • docker + nginx + node.js + php-fpm
  • Passing Control Id from Linkbutton in a gridview
  • Extracting a date from string
  • How do I get partial cell styling in excel using EPpplus?
  • exception thrown while building the java application using netbeans
  • Angular not getting response when it's a non-200
  • List (and connect to) Bluetooth devices from within iOS App
  • Carrierwave default image doesn't display
  • How to position a Widget at the bottom of a SingleChildScrollView?
  • Tableview make specific cell or row editable
  • C# XML Serialization/DeSerialization [closed]
  • Sprite animation wobbly / jumping in IE11
  • Target in barchart in dc.js
  • ggplot2 facet_grid with distinct x-axis labels using facet_grid
  • watir webdriver - window not found
  • Custom progress dialog not working
  • How to organize this layout with overflows?
  • Please update your Node runtime to version >=0.12.x
  • Get name of days between two date in ios?
  • Adding native code to an existing Worklight hybrid app
  • Admob in ListView not clickable
  • Unable to start a WebView from an AsyncTask
  • How to use AJAX to upload large CSV file? [closed]
  • Visual Studio 2017 Professional- Unable to find package at source
  • Request Access Token in Postman for Azure Function App protected by Azure AD B2C
  • time column in sqlite using gorm
  • how to read to huge file into buffer
  • Google Spreadsheet Script to Blink a range of Cells
  • Why is ordered choice in pyparsing failing for my use case?
  • Neo4j…how to get a visual representation of my data?
  • How do I add a mouse over tooltip to an Image using .DrawImage()
  • Another “Cannot make static reference…” Question
  • Unity3d lost directional light shadows after generate assetBundle (.unity3d file)
  • Background transfer download task failed when app was closed
  • Write to .csv file with PHP (Commas in Data Error)
  • How to mutate multiple variables without repeating codes?