6 ms·
Ouch. POSIX did an awful job when it wrote the API for "makecontext". You can't even pass a pointer to the context's function in the natural way, because only
by jepler 8y ago
Ouch. POSIX did an awful job when it wrote the API for "makecontext". You can't even pass a pointer to the context's function in the natural way, because only 'int's can be passed, and on any real computer, sizeof(int) < sizeof(void*)!
And anyway, POSIX removed makecontext in POSIX.1-2008 so new code shouldn't be using it. This is too bad, as there are legitimate reasons to use these kinds of cooperative threading abstractions. I guess we still have gnu pth, which hasn't seen a release in 13 years, but it also has a much bigger (pthreads-like) interface compared to the mere 3 functions in POSIX for cooperative threading.
- klodolph 8y ago> You can't even pass a pointer to the context's function in the natural way, because only 'int's can be passed, and on any real computer, sizeof(int) < sizeof(void*)! I checked the API. It looks like a variadic function, so you can pass any arguments to it?
- josteink 8y agoFor those unaware of the finer nuances of native platform APIs, could you help shed a light on the difference between a “regular” thread and a pthread?
- gpderetta 8y agoMost threading related functions in posix are named with the pthread_* pattern, so pthread (short for posix threads) has become the name of regular (usually OS level) threads on a posix platform.
- jstimpfle 8y agoA "regular" thread I guess is whatever structure the OS has for parallel execution contexts. Sometimes they are subordinate to processes, i.e. a thread dies when its containing process dies and such. pthreads is a standardized API (part of POSIX) that exposes a particular notion of threads. On each platform, it's naturally implemented as a wrapper around whatever the OS can offer. Since it must be widely implementable and have an easy to use API, that also means that it's rather limited. As an example, if you don't want to use the pthreads API, I think on Linux you would use the Linux-specific clone() system call to create a thread (clone() is not part of POSIX). If you go down on that level you will find a wealth of additional Linux-specific thread-related tuning knobs.
- josteink 8y agoThanks for the detailed answer! So basically if I’m used to threads as a general cross-platform concept in higher level languages, I’m probably relating to pthreads?
- jstimpfle 8y agoI suppose it depends on what your concept of threads is. If you're designing a complex system, you're more likely to look at what platforms you must support, and then make up your own (less abstract) notion of threads such that it can be implemented on these systems and that it lets you take more advantage of the capabilities of these systems. I'd be surprised for example if Postgres used pthreads and not its own abstraction, supported by platform-specific implementations.
- jstimpfle 8y agoints are really the best. They are handles, i.e. identities. All my programs use ints almost exclusively. I have a few pointers in function signatures and for global arrays, but the rest is int. When you need a void pointer or whatever information from some fiber, just have an array to map from the handle to that information. Of course, if you are not willing to make a global array for lookup, you are screwed because some additional context is missing.
- kabdib 8y ago... and now you have to synchronize access to your handle table, grow it to meet demand -- let me tell you, that is a fun thing to do when there are thousands of things in flight, all expecting high performance -- and so on. And what NUMA node was that big global array on? Hmmm, I guess you could partition it, but it's kind of awkward and you have to recompute the geometry on every launch and where did you stash that information? TLS? The natural thing for a context type is something that can be used to directly refer to any object. In today's common architectures this is a pointer. Context APIs that don't support "intptr" or something like it are broken.
- jstimpfle 8y agoI don't disagree. I might be in the minority but personally I don't do OS threads as far as possible. They are hard. (And I don't do fibers, either, if I have a choice). But if you do threads, then you could still put that "handle table" into TLS, couldn't you?
- jstimpfle 8y ago> The natural thing for a context type is something that can be used to directly refer to any object. In today's common architectures this is a pointer. Context APIs that don't support "intptr" or something like it are broken. I want to note the huge disadvantage of using pointers, which is that they aren't mathematical identities, but physical identities. It's place vs value. If you use pointers you are absolutely required to have stable addresses, which means you cannot treat data as what it is: information - and you cannot copy it, move it, duplicate and modify it and such. Because the best handle to it that you have is the memory address where it's supposed to live. You cannot even have parallel arrays (which give modularity) but will end up with god objects amassing unwashed unsorted unrelated incoherent junk data because that's the best to get from an address to actual data. While there are valid uses for pointers (and I don't claim to have any relevant experience with threaded applications), today's popular idea that "something that can be used to refer to any object" is best implemented by a pointer is what really leads to terrible, unmaintainable software.
- elteto 8y agoThat's too bad indeed. How would one implement coroutines in Linux/Unix today then?
- sanxiyn 8y agoPython's greenlet extension implements coroutine using inline assembly, which has been widely ported (at least ARM and x86, both 32-bit and 64-bit). It's nicely packaged so that you can use it without Python part.
- gpderetta 8y agoboost has a coroutine api. It provide both low level (untyped C-like) and high level APIs.
- thestoicattack 8y agoI guess wait for libstdc++ to implement the Coroutines TS that got merged into the C++20 standard?
- spc476 8y agoUsually using C's `setjmp()` and `longjmp()` functions (but I consider that an ugly hack). I did an implementation for both x86-32 and x86-64 [1] that works for Linux and Mac OS-X that's for C (written in assembly). I doubt it will work for C++, and I'd be a bit hesitant to use it for production, but it's surprisingly simple. [1] https://github.com/spc476/C-Coroutines https://github.com/spc476/C-Coroutines Edit: clarification of what language my coroutines are implemented in.
- curlypaul924 8y agoWhat should new code be using instead?