25

The user thread functions in <ucontext.h> are deprecated because they use a deprecated C feature (they use a function declaration with empty parentheses for an argument).

Is there a standard replacement for them? I don't feel full-fledged threads are good at implementing cooperative threading.

zneak
  • 134,922
  • 42
  • 253
  • 328
  • You're not understanding what is actually deprecated here. The `makecontext` declaration is absolutely fine and not deprecated - the second argument is literally a function with no arguments. What /is/ deprecated is declaring a function that will take arguments with `()` and later putting the arguments in the definition. You've already accepted an answer that doesn't point this out (a decade ago, ha), but nothing about ucontext.h is obsolete. – BadZen Jan 20 '22 at 02:38
  • 1
    @BadZen, was removed from the [Open Group Base Specification in revision 7 (2018)](https://pubs.opengroup.org/onlinepubs/9699919799/) (you can find ucontext.h in rev 6, but it is absent from rev 7). Glibc still has it, but it's [gone with prejudice](https://pastebin.com/ty8wyqMG) from Darwin. – zneak Jan 22 '22 at 01:33

4 Answers4

21

If you really want to do something like what the ucontext.h functions allow, I would keep using them. Anything else will be less portable. Marking them obsolescent in POSIX seems to have been a horrible mistake of pedantry by someone on the committee. POSIX itself requires function pointers and data pointers to be the same size and for function pointers to be representable cast to void *, and C itself requires a cast between function pointer types and back to be round-trip safe, so there are many ways this issue could have been solved.

There is one real problem, that converting the int argc, ... passed into makecontext into a form to pass to the function cannot be done without major assistance from the compiler unless the calling convention for variadic and non-variadic functions happens to be the same (and even then it's rather questionable whether it can be done robustly). This problem however could have been solved simply by deprecating the use of makecontext in any form other than makecontext(ucp, func, 1, (void *)arg);.

Perhaps a better question though is why you think ucontext.h functions are the best way to handle threading. If you do want to go with them, I might suggest writing a wrapper interface that you can implement either with ucontext.h or with pthreads, then comparing the performance and bloat. This will also have the advantage that, should future systems drop support for ucontext.h, you can simply switch to compiling with the pthread-based implementation and everything will simply work. (By then, the bloat might be less important, the benefit of multi-core/SMP will probably be huge, and hopefully pthread implementations will be less bloated.)

Edit (based on OP's request): To implement "cooperative threading" with pthreads, you need condition variables. Here's a decent pthreads tutorial with information on using them:

https://computing.llnl.gov/tutorials/pthreads/#ConditionVariables

Your cooperative multitasking primitive of "hand off execution to thread X" would go something like:

self->flag = 0;
other_thread->flag = 1;
pthread_mutex_lock(other_thread->mutex);
pthread_cond_signal(other_thread->cond);
pthread_mutex_unlock(other_thread->mutex);
pthread_mutex_lock(self->mutex);
while (!self->flag)
    pthread_cond_wait(self->cond, self->mutex);
pthread_mutex_unlock(self->mutex);

Hope I got that all right; at least the general idea is correct. If anyone sees mistakes please comment so I can fix it. Half of the locking (other_thread's mutex) is probably entirely unnecessary with this sort of usage, so you could perhaps make the mutex a local variable in the task_switch function. All you'd really be doing is using pthread_cond_wait and pthread_cond_signal as "go to sleep" and "wake up other thread" primitives.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 2
    I'm looking for cooperative threading, which is what pthread doesn't do. In cooperative threading/user threading, each thread is responsible for letting the others run. pthreads are scheduled by the OS, which makes it a pain to implement cooperative threading. – zneak Nov 28 '10 at 21:42
  • Perhaps you're looking for conditional variables? https://computing.llnl.gov/tutorials/pthreads/#ConditionVariables – R.. GitHub STOP HELPING ICE Nov 28 '10 at 22:38
  • Added some details on how you might go about doing this with pthreads. – R.. GitHub STOP HELPING ICE Nov 28 '10 at 22:46
  • 1
    I know it's possible (thanks for the references though), but it's much, much less convenient than what getcontext/setcontext offered. – zneak Nov 28 '10 at 22:48
  • If you make a nice wrapper and opaque data structures to represent your threads, the interface should look nearly identical to `ucontext` (aside from the ugly prototype the POSIX folks hated). – R.. GitHub STOP HELPING ICE Nov 28 '10 at 22:50
11

For what it's worth, there's a Boost.Context library that was recently accepted and needs only to be merged into an official Boost release. Boost.Context addresses the same use cases as the POSIX ucontext family: low-overhead cooperative context switching. The author has taken pains with performance issues.

Pavan Manjunath
  • 27,404
  • 12
  • 99
  • 125
Nat Goodspeed
  • 441
  • 5
  • 3
  • That's very interesting. I don't need it anymore, but if I ever need something like that again, I'll know where to look. – zneak Apr 05 '12 at 20:12
6

No, there is no standard replacement for them.

You options are

  • continue to use <ucontext.h>even though they contain obsolete C.
  • switch to pthreads
  • write your own co-thread library
  • use an existing (and possibly not-so-portable) co-thread library such as http://swtch.com/libtask/ , though many of such libraries are implemented on top of ucontext.h
nos
  • 223,662
  • 58
  • 417
  • 506
  • I wonder if these not-so-portable libraries could be ported to use pthreads instead of OS/machine-specific hacks, similar to the approach in my answer... – R.. GitHub STOP HELPING ICE Nov 28 '10 at 22:55
  • 1
    Possibly, but that's a lot more heavyweight. – nos Nov 29 '10 at 08:39
  • I wouldn't say "a lot". A few thousand more cycles to context-switch (or maybe less with SMP/multi-core), and a few extra tens of kb per thread (I would guess 2-4 pages in kernelspace and the same amount in userspace). – R.. GitHub STOP HELPING ICE Dec 03 '10 at 00:17
  • 4
    i would do say a lot indeed; the people that is concerned about using coroutines are definitely concerned about performance, and forcing a context switch just because of pretty design won't help their case – lurscher Aug 31 '11 at 20:52
0

The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 Edition

Still lists makecontext() and swapcontext() with the same deprecated syntax. I have not seen anything more recent.

jim mcnamara
  • 16,005
  • 2
  • 34
  • 51