Path: csiph.com!usenet.pasdenom.info!news.albasani.net!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: Rainer Weikusat Newsgroups: comp.programming.threads,comp.unix.programmer Subject: Re: Open issues in the specification for fork()? Date: Tue, 26 Nov 2013 15:46:33 +0000 Lines: 75 Message-ID: <87li0bmahy.fsf@sable.mobileactivedefense.com> References: <5291d497$0$15884$e4fe514c@news2.news.xs4all.nl> <87hab1kdvw.fsf@sable.mobileactivedefense.com> <52929869$0$15987$e4fe514c@news2.news.xs4all.nl> <20131125011903.172db979@laptop.homenet> <52933db8$0$15988$e4fe514c@news2.news.xs4all.nl> <5293ab24$0$15963$e4fe514c@news2.news.xs4all.nl> <87k3fww2jc.fsf@sable.mobileactivedefense.com> <52945ce1$0$15995$e4fe514c@news2.news.xs4all.nl> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: individual.net u8haMtJ4h7CuAew9TKWYzQaolmECFmvvwMZxQTRvz7jaIv+Y4= Cancel-Lock: sha1:8ocfISNA4Vya9iYnRszA7HOZwRk= sha1:j40iFQd2+212bWiCMHe1TXWd49A= User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux) Xref: csiph.com comp.programming.threads:2020 comp.unix.programmer:5044 Casper H.S. Dik writes: > Rainer Weikusat writes: [M:N/ 1:1 threading] > The argument for "M:N is better" was very strong because, theoretically, > it could be faster and synchronization wouldn't need to use the kernel. > > A "1:1" implementation, in practice, however, uncontended locks don't need a > trip to the kernel either and the enormous amount of extra work needed in > the MxN implementation (handling SIGWAITING, a second implementation of > context switching, which actually often did require kernel involvement) Some people think that 'threads are a way to structure programs', that is, they're primarily supposed to be helpful for developers. The idea is typically that 'a thread of execution' can be dedicated to a single task which progresses intermittently and concurrently with a lot of other tasks of the same kind: In a single-threaded process, this requires storing the state of each task in some 'globally accessible' data structure and continuing to work on some other tasks based on the recorded state of that whenever the 'current task' can't make progress anymore. If each task had a dedicated thread, this wouldn't be necessary because 'the scheduler' would transparently suspend one thread and switch to another whenever things would otherwise come to a standstill, thus providing the illusion that each task really runs on a dedicated computer without having to consider the needs of other tasks. This, of course, requires creating as many threads as there are concurrent tasks and for something like a network server, this could easily mean thousands or even tenthousands of them. Consequently, each thread needs to be as cheap as possible, in particular, it shouldn't have any kernel resources like 'a kernel stack' permanently allocated to it. Also, in order to make programming easy, actual concurrent execution of threads should rather be avoided: For as long as a thread is busy, it just keeps running, and once it invokes 'a blocking call' of some kind, another thread can start to run. In order to avoid starving tasks, threads are supposed to be 'nice to each other', that is, explictly yield the processer every now and then when being busy for a long time. This means cooperative userspace threading. Because there's no concurrency, synchronization isn't really needed and because there's no preemption, no complicated userspace scheduler is needed, either. At least in theory. In practice, once the process blocks in the kernel, all threads stop running and hence, each and every posssible blocking system call must be wrapped in some library routine which accomplishes the same end in some non-blocking way and runs other threads in the meantime. The net effect of this is usually a lot of borderline insane library hackery and some rather bizarre restrictions as to what a thread can do or must not do (the GNU pth paper provides a nice example of that). Some other people think that threads are supposed to be useful for users in the sense that they enable these to utilize processing resources such as multiple processors and/or multiple cores which might be available to them. This implies that 'a thread' runs code which looks pretty much like that of a single-threaded in processes wrt to 'multi-tasking'. In order to keep scheduling overhead down, there will be relatively few threads (somewhat more than available 'processing things') but they're both supposed to execute in parallell and to work with 'shared global resources'. This means synchronization is needed and the kernel scheduler has to deal with them because the kernel is the privileged piece of coding managing the actual hardware and thus, the only software capable of doing things like assigned threads to available processors for execution. Further, this is supposed to work in an environment shared with other application which also seek to use the available resources and which don't have been written to cooperate, hence, preemption is necessary. The most natural choice for this is 1:1 threading where each 'application thread' corresponds with a 'kernel scheduled entity' of some sort. Trying to satisfy both groups of people leads to M:N threading which really just combines the disadvantages of both models without providing the advantages of either. It ends up as expensive way to screw everyone alike but only in practice, not in theory. I was planning to illustrate this using the pre-Solaris 8/9 'threading workarounds' as example but this text is too long already ...