8 ms·
Show HN: uThreads – Concurrent User Threads in C and C++
- anonymousDan 10y agoInteresting, I've recently been looking for a user level threading package in C/C++. I ended up settling on lthreads: http://lthread.readthedocs.io/en/latest/intro.html http://lthread.readthedocs.io/en/latest/intro.html Does anyone know how it compares?
- RotsiserMho 10y agoI haven't tried either but I've been meaning to take a look at https://github.com/Amanieu/asyncplusplus https://github.com/Amanieu/asyncplusplus.
- saman_b 10y agoHi, I developed uThreads. I looked at lthreads quickly, and it seems lthreads only maps multiple coroutines onto a single pthread (N:1). Although, it adds the possibility of running multiple pthreads, but each pthread can only run their local lthreads (using M threads that do N:1 mapping). However, in uThreads, uThreads can be multiplexed over multiple pthreads (thus M:N mapping). Also lthreads scheduler is based on epoll/kqueue per pthread, and uThreads is using run Queues to manage uThreads which has less overhead. Per pthread epoll/kqueue can mean better scalability for large number of threads in comparison with uThreads that is relying on a single poller thread. But since the poller thread and synchronization is very low overhead in uThreads, the scalability is not an issue (Experiments to up to 16 threads show that uThreads scale very well). Although lthreads provide compute boundaries and async IO to move lthreads over other pthreads, but this process seems to be very expensive. uThreads does not provide these features, but it provides more flexibility and control to the developer by providing migrations. Developers can use migration at any point to move the uThread to another set of kThreads to execute tasks asynchronously (By defining Clusters of kThreads, e.g., IO cluster or Compute Cluster).
- scott_s 10y agoI recommend trying to get access to larger machines with more hardware parallelism. I have seen techniques that scale just fine to using 16 threads, but hit serious limitations when you get to over 100 threads.
- saman_b 10y agoYou are right, I have access to machines with higher number of cores, but they have multiple sockets and at some point I need to address the cross NUMA cost which adds a whole new level of complexity and design decisions. For sure at some point the poller thread will be saturated and the program will not scale past a certain number of threads. I used to have a poller thread per cluster for better scalability, but that would add overhead for migrations between clusters, thus I had to remove it for now until I can somehow find a low overhead solution. uThreads is a work in progress and all these need to be carefully considered in the future :) Thanks for your feedback
- scott_s 10y agoSometimes, the techniques you use to scale to 100s of threads solve some NUMA issues by virtue of the fact that in order to scale that high, you need to avoid touching as much non-local data as possible. I think it's better to just deal with the pain now and start running your experiments on as large of a machine you can get access to. You can still put off explicitly designing for NUMA, but you want to avoid spending too much time and effort designing for the lower end of the scalability spectrum.
- ndesaulniers 10y ago> uThreads is using run Queues This sounds like the Linux kernel. I'm curious to understand why copying this logic into user space is worth while?
- saman_b 10y agoI am not sure if you are referring to the runQueue being used in Linux or the whole approach. I try to answer both: Run queues can be part of any scheduler, they are queues with runnable tasks. But as why the approach is worth while in user space, it has to do with low cost of operations (context switches) in user space, and also using cooperative scheduling instead of preemptive. Cooperative scheduling provides more control to the user over the tasks, and also has lower overhead since there is no need to manage a quantum for each taks (thread).
- krat0sprakhar 10y agoThis looks super interesting! I've been working on a Raytracer in C++ and I was recently looking into a threading library which I can use to parallelize the rendering. Surely going to try this out in the coming weekend. Unsolicited suggestion - while benchmarks and the motivation are important for a threading library, a code snippet of a simple parallel program on the home page would be something that I'd love to see. Great job, though!
- saman_b 10y agoThanks! good point; now that I look at the page, there is not a single sample code in there. I'll update it soon.
- krat0sprakhar 10y agoAwesome! As an example, Rayon[0] does a very good job (IMHO) at this. [0] - https://github.com/nikomatsakis/rayon https://github.com/nikomatsakis/rayon
- saman_b 10y agoThanks, oh all those fancy functions. I need to improve the interface a bit, as for now everything is only based on using uThreads as the unit of concurrency. e.g., this is a recursive Fibonacci: https://github.com/samanbarghi/uThreads/blob/master/test/Fibonacci.cpp https://github.com/samanbarghi/uThreads/blob/master/test/Fib... and a fork-and-join Fibonacci: https://github.com/samanbarghi/uThreads/blob/master/test/FibonacciFJ.cpp https://github.com/samanbarghi/uThreads/blob/master/test/Fib... There is no fork-and-join in uThreads yet, and I created it using create and join. The interface will improve in the future :)
- zokier 10y agoIsn't raytracing almost completely CPU-bound? Seems like a odd use-case for green threads, which afaik are more commonly used for IO-bound tasks.
- 10y ago
- deleted 10y ago[deleted]
- valarauca1 10y agoImpressive. 8KiB stacks are a bit on the small side though for production usage. Go gets away with this because they're stacks act more like Vectors then flat arrays. Why did you decided to roll your own stack swapping software instead of using say using `boost::context`?
- saman_b 10y agoRight, however segmented stacks are have high overhead and stack copying is not very easy in C/C++. Thus, for now uThreads only support fixed size stacks, I know it makes it harder to be used in production, and in the future I might provide optional segmented stacks. As for why not using `boost::context`, I am implementing uThreads as part of my research in uwaterloo, I wanted to have full control over the code and be able to optimize for performance as much as I can. Thus, tried to avoid relying on any third party code when I started :)
- pg_is_a_butt 10y agoand yet you're relying on a compiler and linked libraries you didn't write. you're all idiots.
- jtsylve 10y agoIs there any reason you chose GPL3 or would you consider a less restrictive license like Apache or BSD?
- protomikron 10y agoCan we please stop calling out nearly every project that uses GPL (3) and call it restrictive? I know there are different opinions and arguing which is "better" nearly always leads to a philosophical debate on principles that gets us nowhere. Sorry if this sounds snarky, and I do not blame you in particular, but it is just a theme I have encountered here the last years that I find toxic as it portrays the GPL (and FSF) as some evil organization that would restrict "developer's rights".
- module0000 10y agoNot sure what the OP's motivation are for asking "why GPL?", but my motivation when I ask that can translate to something like this: "Hi, I'd like to use your library, but your license is incompatible with the other <N> licenses in my codebase. Consider BSD please?"
- llukas 10y agoIt's not like GPL v3 prevents guy from contacting the author and offering him $ for license.
- protomikron 10y ago"Don't ask the author of a library why it is incompatible with proprietary licenses. Ask why your codebase is incompatible with open licenses." JFK
- jtsylve 10y agoI don't think that the GPL or the FSF is bad or evil. I've released and maintain several projects that are GPL licensed. GPL is by definition more restrictive than Apache and BSD, since there are more requirements to use the code, so asking if the developer is willing to consider a less restrictive (not "better") license shouldn't be met with hostility. My motivation for asking is simply because the project looks interesting and potentially useful; however, the proprietary nature of my current work means that GPL licensed code isn't really an option for me. I absolutely wouldn't hold it against the author if they chose GPL for this or any other reason.
- michaelsbradley 10y agoFor what kinds of applications would one favor this over, say, the coroutines approach of libdill? http://libdill.org/tutorial.html http://libdill.org/tutorial.html See, in particular, Step 6 of the tutorial.
- saman_b 10y agoIn libdill approach, you are probably limited to only multiplex connections over multiple kernel threads. And when a connection is accepted over a kernel thread it has to perform all further instructions over that kernel thread. So it gives you a bit of control over which cores to be utilized but after that you do not have control over what part of the code should be executed on each core. Using uThreads you can decide what part of the code should be executed over each kernel thread and, if taskset is used, which core to execute your code. You can do this by creating Clusters and using migration or uThread creating in runtime. Thus you can decide which thread is used to multiplex connections and which one is used to run CPU bound code in addition to having a thread pool for example to do the disk IO asynchronously. Ultimately, one can create a SEDA[1] like architecture using uTrheads. Also you can always use uThread as a single threaded application. ------------------------------------------ [1] https://en.wikipedia.org/wiki/Staged_event-driven_architecture https://en.wikipedia.org/wiki/Staged_event-driven_architectu...
- michaelsbradley 10y agoFirst time I've heard of SEDA, though I've been aware of the concerns/concepts it addresses, in various forms, for some time. Any thoughts on Welsh's Retrospective on SEDA? http://matt-welsh.blogspot.com/2010/07/retrospective-on-seda.html http://matt-welsh.blogspot.com/2010/07/retrospective-on-seda...
- saman_b 10y agoI have seen this before. Those are very good points, and I am trying to move this library towards supporting a SEDA type architecture with dynamic control and auto tuning runtime parameters.
- naasking 10y agoWhy not just use StateThreads? A comparison against other options would be illuminating.
- saman_b 10y agoGood idea, I probably write a blog post on this later. If you take a look at [1], I explain the difference between N:1 and M:N mappings. StateThreads uses a N:1 mapping which means you can multiplex many fibers over a single thread and to take advantage of multi-processors you can have M processes that do N:1 mapping, which is a common practice (libmill, libdill, ...). But with uThreads you can multiplex many fibers over many kernel threads. --------------------------------- [1]https://github.com/samanbarghi/uThreads#what-are-uthreads https://github.com/samanbarghi/uThreads#what-are-uthreads
- naasking 10y agoSure, I get the M:N argument, but that wasn't something you could extend existing solutions to support?
- saman_b 10y agoDo you have anything specific in mind? The only code I found similar to this is uC++ [1], which has way more features and more sophisticated scheduler. I am using this as part of my research and wanted to have sth very simple. For all N:1 mappings, since there is only a single process, there is no need for synchronization, also there is no need for any scheduler as a simple queue suffice. But as soon as multiple threads are introduced, there is a need for orchestration among threads and it also changes all other aspects of the code. Of course, I could develop on top of an existing codebase, but I suspect I had to change so much that it is better to start from scratch anyway. ------------------------------------ [1]https://plg.uwaterloo.ca/usystem/uC++.html https://plg.uwaterloo.ca/usystem/uC++.html
- naasking 10y ago> For all N:1 mappings, since there is only a single process, there is no need for synchronization, also there is no need for any scheduler as a simple queue suffice. Wouldn't an M:N model simply amount to work stealing among N kernel-thread-local queues? This seems like it should be a pretty straightforward extension to one of the user-level C thread packages. Or are you doing something more elaborate for your research?
- purple-dragon 10y agoI've had success with Intel's Threading Building Blocks. Is there a reason I might prefer something like this instead?
- saman_b 10y agoSeems like a very mature library, I can't answer your question before I go through their documentation and code. Also, I find your question a bit abstract, since I am not aware of the details of the problem you are trying to solve, I cannot reason why any library or tool can be better over other libraries. In your case, TBB might fit your requirements and it might be hard to give a reason to switch to another library.
- jcbeard 10y agoHow would something like this differ from something like Sandia National Lab's Qthreads (http://www.cs.sandia.gov/qthreads/ http://www.cs.sandia.gov/qthreads/)? Seems it's a tried and true solution in C that also works with C++11 (committed a test case for C++11 myself)...It is also an optional underpinning for some relatively big-name frameworks like Kokkos, Chapel, RaftLib, etc.
- saman_b 10y agoThanks for mentioning this, it is indeed very related and very interesting. I am not sure why not me or people around me were aware of Qthread, it has very good support for various architectures and provides many interesting features. It has many similarities with I have in mind for a concurrent library, and even some research goals seems to be very close to mine. Specially the notion of affinity and locality is what I am focusing on in uThreads. I am going through the papers and the source code at the moment to see what are the similarities and differences. uThreads is still a work in progress and I have specific plans for it in the future that might differ of what Qthreads is trying to accomplish. For now my focus is more on providing auto tuning of Clusters based on the workload. I also will try to explore the pros and cons of uThread migration based on Cluster placement (NUMA and cache locality), and from the 2008 paper it seems that it is what you are trying to study as well. I am open to collaboration if there is an ongoing study around this topic.
- jcbeard 10y agoooh, ok. you might also check out openshmem (http://openshmem.org/site/ http://openshmem.org/site/) and openucx (http://www.openucx.org http://www.openucx.org). I'd been planning on integrating both in RaftLib just not enough cycles to get it done yet. These combined would make it much easier to maintain a relatively portable yet performant back end. My thesis research was all about locality, memory placement, and throughput for big data systems. Current work is similar but I'm not neck deep in the hardware dev world. There are current research efforts on my part outside of work, most center around the raftlib.io platform. Before I forget, you might also want to check out the graph partitioning frameworks like metis and scotch...both are used in some MPI frameworks for more optimal partitioning. To get topology data you might want to look at the hwloc framework, it's cross platform and provides input for things like NUMA/cache/PCIe topology for optimization. I haven't had a chance to integrate this hook into RaftLib, however it's just a few lines away once I find the time. If you're wondering...I started out writing my own fiber library for RaftLib. Had ports for both IBM Power and Intel, but it gets a bit tiring maintaining/optimizing for every new architecture. Qthreads and the like have been used in HPC circles for quite awhile, so it made sense. There was no way I was beating them for dev time, so might as well join them. Based on your auto-tuning discussion...RaftLib aims to do something similar, but for big-data stream processing workloads. Here's my 2016 IJHPCA paper: http://hpc.sagepub.com/content/early/2016/10/18/1094342016672542 http://hpc.sagepub.com/content/early/2016/10/18/109434201667... It looks like it's behind a paywall so if you don't have access I'll update my website with the "author archive" copy sometime today...will be at ( http://jonathanbeard.io/media http://jonathanbeard.io/media ) once I update it. Bottom line if there's intersected interest, definitely open to collaboration :).
- medi11 10y agoHow does it compare to boost.fiber (http://www.boost.org/doc/libs/1_62_0/libs/fiber/doc/html/index.html http://www.boost.org/doc/libs/1_62_0/libs/fiber/doc/html/ind...)?
- avdicius 10y agoI did something similar in plain C: https://github.com/ademakov/MainMemory https://github.com/ademakov/MainMemory