crystal-lang

Making a blocking call asynchronous


I'm using Crystal bindings for X11 and typical usage looks something like this:

loop do
    event = display.next_event # <- blocking!
    # do stuff with event
end

This works fine but I can't do anything in parallel now because next_event is native C code and thus never yields.

xlib's NextEvent is always blocking, also in C. There's a thread about it with possible alternatives, but polling is slower and more CPU demanding than next_event, so I'd like to stick to that blocking call. Do I have to put this into its separate OS thread? -Dpreview_mt actually solves this, but that's an experimental flag and makes all concurrency threaded which is unnecessary (edit: Just found out, this is not true, there is spawn same_thread: true do syntax). What options do I have?

Edit: I just found this is discussed in more detail in this thread which is worth reading on the topic. There's also FileDescriptor's wait_readable which can resolve this if you can obtain a FD somehow.


Solution

  • When a lib function blocks, you can't do anything about it in Crystal. You will need to run it in a separate OS thread in order to be able to run other code in parallel. That's what such methods are designed to be used for.

    In Crystal, you don't need preview_mt to just run a separate OS thread. This flag enables multithreaded scheduling for the Crystal runtime. For your use case, you actually just need a dedicated thread to wait for a blocking call to finish. The thread API is not publicly exposed, but you can use Thread.new { } to create a new OS thread and run the proc in that thread.

    I think we'll need to add a public API for such use cases to the language. But currently, it's not documented (so it might be subject to change, but that's unlikely).