Ignoring complaints about the introduction of a new style of _Identifier, the rant about pthreads seems myopic or just plain wrong.
For a start as a vendor-neutral spec (the C standard itself), pthreads would never be adopted as-is. It simply couldn't happen for political reasons (without knowing a thing about the internals of the working group, I'm fairly confident of that). In the meantime it is still useful to define some uniform cross-platform API, even if most organizations continue to use pthreads in legacy code.
Assuming "too dangerous" wasn't a direct quote: stack size is an implementation detail, something they probably intentionally left undefined. There are good reasons for this, not least baking assumptions about the underlying machine into the standard has never been a goal. Secondly, with advances like Go's dynamic stacks and its <5 assembly instruction overhead, why would you go and bake a feature akin to a modern sbrk(2) in when sexy alternatives that might see wider adoption are already seeing deployment.
As for timed sleeps, providing absolute timestamps rather than intervals is important because it prevents drift: given any function manipulating time, or some timeout, calculating some perceptible end time in the function prologue is much more immune to stupid developers introducing drift (via loops), than expecting the average Joe to account for the latency/contention introduced by system calls, the scheduler, power management, etc.
Fears regarding ntpd causing sudden jumps aren't well-founded (ntpd adjusts time very slowly, in sub-second intervals), although the general argument is fair (the sys admin, or other crazy external sources, can cause large time jumps).
Pthreads has been the standard for 20 years, either you do better than it does, or you are wasting everybodys time, including your own.
"Too dangerous" is a direct quote from a WG14 member.
Stacksize is not an implementation detail, it often is crucial resource management issue for each individual application, in particular in high performance computing and network service applications. The C1X thread API provides no way you can set it.
With respect to timed sleeps: You can simulate wall-clock sleeps with duration-sleeps, but not the other way around. Just that simple fact should make it clear why the API, if it can only offer one kind of timeout, should offer duration-sleeps.
NTPD will step your clock up to +/- 3599 seconds. I happen to know: I helped write it.
With respect to stack size, I still believe it is an implementation attribute independent of the abstract machine for which C is specified. There is no reason why some undefined external vendor-specific control (e.g. some glibc function) can't be provided by implementations, where required (however as in the example I gave, implementations are possible where such a control would be meaningless - its inclusion would be myopic).
Following your argument, complex systems could not be designed without similar controls on memory allocator behaviour ("how can I allocate anything when I don't know if malloc() will introduce syscall latency for a size-32 allocation!?") or environment table size ("how can I possibly execute a subprocess if I can't be certain setenv() will always succeed!?").
The answer to both of course is that you don't design for the standard, you design (and measure) for a particular closed system. I can't see why stack size is any different from the two (of many) examples above.
Re: absolute timeouts, the impossibility of emulating intervals reliably with wall-clock is a very good point.
First: Why should the API for setting stack-size be implementation defined, when a stack mandated to implement the language ?
Second: You seem to labour under the misunderstanding that all threads in a program have, and should have the same stack size ? That's simply not true, you can look in Varnish for a good example: We may have 10 "overhead" threads with big stacks and 100.000 worker threads with small stacks.
Third: You cannot add "some glibc function" to set the stack-size of a thread you have not yet created, and setting it afterwards may be impossible (if you want it larger) or cause memory fragmentation (if you want it smaller).
Fourth: What does malloc(3) have to do with thread stacks ??
For the third time, the API for setting stack size should be implementation defined because there are perfectly practical implementations for which any specification would be meaningless.
Another reason is that almost all prevailing contemporary environments use virtual memory, and the prevailing embedded architecture (ARM) is about to go 64 bit (the desktop/server world already has). In a world with virtual memory, paging, and even where we're 10 years away from "complex system" interconnects powerful enough to provide shared memory across 10k+ computers filling a football field, how much longer would setting the stack size have any practical meaning.
It would be like insisting on a frewindtapedrive() library call, because your machine happens to have a tape drive (and aren't files stored on tapes eventually!). Thankfully you weren't on the committee in the 1980s. ;)
Nowhere did I suggest all threads should have the same stack size - if anything by the Go example, I suggested they might have no specific 'size' at all.
malloc(3) has nothing to do with thread stacks, it was just an example of yet something else that has very implementation-defined behaviour, for which any standardized tuning API would probably come up short.
> almost all prevailing contemporary environments use virtual memory
IBM's Compute Node Kernel (Blue Gene) uses offset-mapped memory (no TLB). This is great for reproducible performance (much less than 1% variability on thousands of cores, compare to 30% or more on Cray). Admittedly, most jobs running on CNK will use constant stack sizes across all threads, but not all.
The C standard does not specify that the language be implemented using a stack at all, so it would be inconsistent to provide an API for manipulating stack sizes.
> Another reason is that almost all prevailing contemporary environments use virtual memory, and the prevailing embedded architecture (ARM) is about to go 64 bit (the desktop/server world already has). In a world with virtual memory, paging, and even where we're 10 years away from "complex system" interconnects powerful enough to provide shared memory across 10k+ computers filling a football field, how much longer would setting the stack size have any practical meaning.
I set the stack size on my worker threads because I don't want my users looking at my process in 'ps', see a big VSIZE, and conclude that my software is bloated and memory hogging. Yes I know I can educate my users but I would rather prevent them from bothering me with these false conclusions in the first place.
> This is currently implemented for 32-bit and 64-bit x86 targets running GNU/Linux in gcc 4.6.0 and later. For full functionality you must be using the gold linker, which you can get by building binutils 2.21 or later with --enable-gold.
Too bad it is not part of the ABI specification on any known platform, so if you call a library function compiled without this magic compiler you're totally screwed.
But an interesting research project, I'll grant you that.
Thread stack size is an important performance tuning knob. If your app has 100,000 threads you really do care about running out of memory. If you have 10 threads you don't care. You should of course separate the choice of stack size from your application code. Your library still needs to support this.
"providing absolute timestamps rather than intervals is important because it prevents drift"
I don't know what you mean by "drift". When I put a timeout on a threaded operation (joining, acquiring a mutex, etc.) I am guarding against blocking forever 99% of the time. It is much cleaner to say "this should take no more than 5s" vs. "this should end at XYZ time UTC". Forcing the application to track elapsed time in the face of NTP etc. sucks. Letting the library handle those edge cases is good. It can use a CPU tick counter or similar.
"Fears regarding ntpd causing sudden jumps aren't well-founded (ntpd adjusts time very slowly, in sub-second intervals)"
What if I am sleeping in sub-second intervals? This goes to the general thrust of PHK's article. He is endorsing K&R C and pthreads because they give you minimal tools that can express a very wide range of programs. Building assumptions about how long people want to sleep for into an extremely widely deployed standard is a mistake.
Your comments on thread stack size don't contradict the parent's point. Thread stack size is an implementation detail, and it's also an important performance tuning knob. That implies that it should be a knob that belongs to the system, not the C standard.
Do you mind elaborating on the supposed political quibbles that would prevent a pthreads-like API from being adopted? Are you are implying that vendors of competing API's would oppose anything pthread-like making its way into the standard?
If you read the minutes they borrow generously from PThreads. But I can imagine some major vendors, like Microsoft, may say, "We have a threading library where PThreads conflicts with how we do threading. Rather than just taking PThreads as a whole, lets look at these issues and come up with a solution that will work reasonably for everyone."
Otherwise you end up with C1x coming out and MS just saying, "This is broken for Windows. Our compiler won't implement it." And just let gcc and Intel pick up the load. Which may be fine for some, but seems counterproductive.
FWIW, Microsoft does not bother with C99 not because they are lazy, but because I honestly never remember C being "the focus" at all: they have been strong backers of C++ since before I started doing Windows development (which itself was back in 1994). They mostly seem to ship a C compiler only because it is often easy to dumb down their C++ compiler to do so (and even then, C++-isms sometimes slip into their C modes).
"""Thanks for submitting this suggestion. I've resolved it as Won't Fix, because we currently have no plans to implement C99 Core Language features. While we recognize that a few programmers are interested in those features, our finite development and testing resources force us to focus on implementing features that will have the greatest impact on the greatest number of programmers, which means C++."""
"""Unfortunately 1) There are many, many more users of the Microsoft C++ compiler than there are of the C compiler; 2) Anytime we do customers discussion and/or solicit feedback the overwhelming response is that we should focus on C++ (especially at the moment C++-0x); 3) We just don't have the resources to do everything we would like. So while we are slowly improving our C-99 support (and we are active in the C-1x discussions) I can't promise we'll add any of these features."""
Fortunately, there exist at least two decent C compilers for Windows that I know of: GCC and ICC. GCC provides the same FOSS compiler available on every other platform, and also allows cross-compiling from FOSS platforms to Windows, which helps when producing cross-platform binaries (to avoid needing to have a Windows system around to build release binaries). ICC doesn't use a FOSS license, and it lags behind GCC, but it does provide a replacement backend for Visual C++, which can make it more usable in some environments. Either one provides much better support for C than the Visual C++ C compiler.
Oddly, that might be the best place to be. If it worked for 50% of the group, there might not be enough votes to get it changed (the 50% can effectively block progress). If it works for nobody, then there's still a chance it can get changed.
And then people wonder why I'm not the guy in the room who is generally not excited about standards.
For a start as a vendor-neutral spec (the C standard itself), pthreads would never be adopted as-is. It simply couldn't happen for political reasons (without knowing a thing about the internals of the working group, I'm fairly confident of that). In the meantime it is still useful to define some uniform cross-platform API, even if most organizations continue to use pthreads in legacy code.
Assuming "too dangerous" wasn't a direct quote: stack size is an implementation detail, something they probably intentionally left undefined. There are good reasons for this, not least baking assumptions about the underlying machine into the standard has never been a goal. Secondly, with advances like Go's dynamic stacks and its <5 assembly instruction overhead, why would you go and bake a feature akin to a modern sbrk(2) in when sexy alternatives that might see wider adoption are already seeing deployment.
As for timed sleeps, providing absolute timestamps rather than intervals is important because it prevents drift: given any function manipulating time, or some timeout, calculating some perceptible end time in the function prologue is much more immune to stupid developers introducing drift (via loops), than expecting the average Joe to account for the latency/contention introduced by system calls, the scheduler, power management, etc.
Fears regarding ntpd causing sudden jumps aren't well-founded (ntpd adjusts time very slowly, in sub-second intervals), although the general argument is fair (the sys admin, or other crazy external sources, can cause large time jumps).