Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

New API Thread Call #5191

Closed
jvburnes opened this Issue · 3 comments

2 participants

@jvburnes

I'd like to suggest a new, portable thread call for yielding the processor to the next runnable thread. This is useful when writing lock-free message code and a producer/consumer detects a resource contention issue.

Justification vs Other Techniques

  • You can spin-lock in these instances, but sometimes the spin-lock can freeze the other side out resulting in dead lock.
  • You could yield the processor immediately (to the OS or to the event loop), but the cost of doing a context switch out and in again can be up to 16,000 processor cycles.
  • You could do a limited spin-lock (say up to some percentage of a context switch) and then yield to the event loop which would allow other events to be processed. This would be fine except that the thread yield often occurs deep in the logic of a very state-dependent callback which you don't want to have to re-trace. Also the thread is likely not directly attached to an event loop.

Since most libuv thread calls follow the 'pthreads' format, I'll call it:

int uv_thread_yield();

The semantics for yielding a thread on POSIX vs Windows are fairly similar.

On POSIX (IEEE Std 1003.1-2008) this would generate a call to:

int sched_yield();

Which almost always succeeds. If it does fail, it returns -1 and sets errno. (On Linux it can never fail.)

(This is the POSIX generic equivalent to pthread_yield() and should be more portable).

On Windows API we would call:

BOOL WINAPI SwitchToThread();

Which has been available on the server-side since Win2K3 and on the desktop since WinXP. This call attempts to yield the CPU to the next runnable thread on the same processor.

On Windows it returns non-zero (BOOL true) if the processor yielded or zero if no runnable process on this processor exists. In this case no yield would have occurred.

On both platforms, if the yield fails you should probably return to a blocking wait condition (or an idle_sleep if nothing else). Of course this is app and situation dependent.

In libuv these semantics should probably be standardized to POSIX semantics so that

int uv_thread_yield();

Returns:
0: On success
-1: On error, with uv_last_error() returning a meaningful error

I'm not asking anyone else to write this code. It's fairly trivial, but I'd just like to suggest it so that I don't have to write #if defs in an app that uses a portable thread library.

(Question: Since uv_thread_yield can occur outside of an event_loop, how do you retrieve the uv_last_error which requires a loop?)

@jvburnes

Sorry. I think I should have posted this to the joyent libuv github. Please let me know if I should repost.

@bnoordhuis

I'm okay with the general concept but can you create a libuv issue for this?

@bnoordhuis bnoordhuis closed this
@jvburnes

This discussion has moved to the 'libuv' issues list at: joyent/libuv#760

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.