Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Strictly speaking you're right, it's not really about kernel threads. It's about concurrency.

Proper pre-emptive threads in the kernel aren't the only way to achieve that: Java used to use 'green threads' rather than kernel threads. Its advice on using worker threads to keep your Swing application nice and responsive [0], would still have applied. (I believe this is still the case today for GTK programming in Python, which still uses green threads.)

Most GUI toolkits use C-based languages and compile to native code. Cooperative multithreading isn't a popular model in C-family languages, but I can't see a good technical reason that it wouldn't work (after all, it boils down to something akin to green threads with finer control).

A well-designed Qt app (in C++) will use worker threads to keep the UI thread responsive [1]. It doesn't matter if the worker threads run on a different core, or on the same core through time-division multiplexing. It's not a question of compute-throughput. What matters is that the UI thread doesn't get blocked for long.

[0] https://docs.oracle.com/javase/tutorial/uiswing/concurrency/... [1] https://doc.qt.io/archives/qq/qq27-responsive-guis.html



> Strictly speaking you're right, it's not really about kernel threads.

I'm not particularly interested in being right or wrong, but, rather, improving understanding.

The reason I made the (strict) distinction was that the whole discussion has been about kernel-supported file locking. Anything called "threading" outside of the kernel seems inapplicable, no matter how closely related conceptually or in practice.

Of course, I may be missing something, such as if userspace/green threads both significantly preceded kernel threading support and motivated its implementation (presumably by benefiting from it).


> I'm not particularly interested in being right or wrong, but, rather, improving understanding.

Sure, I hadn't meant to seem combative.

> the whole discussion has been about kernel-supported file locking. Anything called "threading" outside of the kernel seems inapplicable, no matter how closely related conceptually or in practice

Is it necessarily inapplicable? You could write a Python program that uses file-based locking, despite that Python threads don't map to kernel threads, no?

Or in C, you could have 'fake threads' where you effectively bounce control around between a few different execution streams (something akin to coroutines or fibers). We could still reason about which 'thread' holds the file lock, despite that there's only one kernel thread. (Aside: the GNU 'Pth' library does something like this.)

> such as if userspace/green threads both significantly preceded kernel threading support and motivated its implementation

I think interpreters tend to use green threads simply for ease of implementation, more than for anything else. I suppose it helps with cross-platform concerns, but these days, it's quite possible to write multi-platform concurrent C/C++ code. Green threads aren't so popular today, now that multicore is the norm.

Long ago, processes predated (kernel) threads. Before my time, but I believe the general idea then was that if you want the kernel to orchestrate concurrent execution (including executing in parallel on multiple cores if possible) then you'd just have to bite the bullet and go multi-process.

Today we still see some use of process-level concurrency/parallelism, such as in Postgres.


> Is it necessarily inapplicable? You could write a Python program that uses file-based locking, despite that Python threads don't map to kernel threads, no?

Sure, but what would be the point? I'm looking for legitimate motivations, not contrived examples of what's merely possible. Remember, we're talking about single-core, single-process, multi-threaded for responsiveness (e.g. in a GUI) here. That single process wants to use kernel file locking?

> Long ago, processes predated (kernel) threads. Before my time, but I believe the general idea then was that if you want the kernel to orchestrate concurrent execution (including executing in parallel on multiple cores if possible) then you'd just have to bite the bullet and go multi-process.

By the time Unix-based MP systems became common (all single-core at the time, just multi-socket), those OSes tended to have kernel threads and at least lightweight processes. I can't recall when SunOS 4.1 got it, but I think it was around '91 if not before, but Sun was pushing SunOS 5 aka Solaris 2 for their big SMP boxes https://www.dre.vanderbilt.edu/~schmidt/PDF/beyond_mp.pdf

Before that, there wasn't much biting of any bullets, as I recall, as the challenge was time-sharing the scarce resource that was a CPU, not parallelism. Frequent context-switching, process or even thread, would be the performance-killing worry for something real-time like a GUI on a computer with a single user. Per Moore's Law, today's CPUs have something like 11000x the transistor density of the ones in '91.


> what would be the point

The point of my comment there was that I'm not sure what you meant by 'inapplicable'. It would work, right?

As you say, it seems unlikely you'd ever want to use file locks for intra-process concurrency when you could just use the mutex machinery of your language's standard library. The use of green threads doesn't change things at all.

> the challenge was time-sharing the scarce resource that was a CPU, not parallelism

The question there is how pre-emption works, right? They're non-cooperative threads after all. If I understand correctly, Solaris used not to have a direct mapping from userland threads to kernel threads (I'm not sure how the multiplexing worked), but they later moved to a direct mapping (every thread really is backed by a kernel-managed thread).

(I could be completely wrong about that, I just skim-read the 'Solaris Internals' book once.)


> The point of my comment there was that I'm not sure what you meant by 'inapplicable'.

Inapplicable to the context of the over-arching discussion, which is POSIX advisory file locks.

These are not the "threads" you're looking for.

>>> Are you saying that the only reason people would want threading capabilities is to exploit multicore/multiprocessor architectures?

So, to recap, yes, I'm saying the only reason people would want kernel threading capabilities (the only threading capabilities applicable to the topic at hand) is to exploit multicore/multiprocessor architectures.


> the only threading capabilities applicable to the topic at hand

If we're going to discuss the merits of kernel threads, it doesn't make sense to do so in a vacuum.

> I'm saying the only reason people would want kernel threading capabilities [...] is to exploit multicore/multiprocessor architectures

Didn't we already discuss this? The answer is no.

Preemptive multithreading of native-compiled code, is a popular concurrency strategy. I gave the example of Qt. GUI toolkits based on C/C++ could use userland-based cooperative multithreading to keep things responsive, but they don't. They use kernel threads, for reasons which have nothing to do with parallelism.


> Didn't we already discuss this? The answer is no.

We did, but you never made the case for the answer being no, which means the answer is still yes.

> GUI toolkits based on C/C++ could use userland-based cooperative multithreading to keep things responsive, but they don't. They use kernel threads

That's descriptive, not normative. You haven't said why that's the case, or, more importantly, why, in the absence of kernel threads, someone would want them to exist only for GUI responsiveness types of use cases.

Your earlier admission led me to believe they wouldn't:

> Cooperative multithreading isn't a popular model in C-family languages, but I can't see a good technical reason that it wouldn't work (after all, it boils down to something akin to green threads with finer control).


> you never made the case for the answer being no, which means the answer is still yes

The widespread use of preemptive concurrency for reasons aside from parallelism, demonstrates my point.

> You haven't said why that's the case

If I had to guess, I'd go with this: it's the easiest option for the C/C++ languages and developers, considering how existing functions tend to be blocking, and that C/C++ programmers are more likely to be familiar with preemptive concurrency than cooperative concurrency.

You certainly wouldn't want to use a model that relies on, say, continuations. Intel's TBB library does this. It's a very good library, but the user must write pretty hairy C++ code, despite the benefits of modern C++. It's no help that continuations are trivial in, say, modern C#.

Fibers/coroutines can be done with external C/C++ libraries, but it's seen as a pretty exotic thing to do.

> why, in the absence of kernel threads, someone would want them to exist only for GUI responsiveness types of use cases

Looks like Windows first got 'proper threads' in Windows 98. I suspect it's not purely for GUI, but for other types of application too, such as servers. Again I suspect the reason they're used in preference over the cooperative alternative, is largely just what people are used to.

Looks like Windows provides fibers for C++, so it's not like they've never heard of them. [0]

> Your earlier admission led me to believe they wouldn't:

Sure, I'm not hating on cooperative multithreading. They have advantages: fine-grain user control, no unexpected interleaving, better performance regarding switching. Bit of a pity it's not often used, I suppose.

I google'd the question, but didn't find a decent exploration of why they're so rarely used. This StackOverflow answer thinks the answer is technical, but I'm not convinced. It seems to discount asynchronous IO. https://stackoverflow.com/a/16766549/

[0] https://docs.microsoft.com/en-us/windows/desktop/procthread/...


> The widespread use of preemptive concurrency for reasons aside from parallelism, demonstrates my point.

If your point is that kernel threads are more attractive that the alternative, once they already exist, then yes, but that continues to miss refuting my assertion.

Using something ("off label"[1]) once it's already there, isn't the same thing as wanting/needing it in the first place.

[1] consistent with my assertion that the "label" for threading specifies its use for multiprocessor support. After all, how did the early X server or Sun's NeWS manage to be so responsive before all that newfangled threading stuff in the 90s?


> how did the early X server or Sun's NeWS manage to be so responsive before all that newfangled threading stuff in the 90s?

Good question. I have no idea.

If my intuition is accurate, systems like the DOOM engine just crunch through each frame's workload as a sequential queue, tending to things like the audio buffer whenever necessary. I don't know if there's any asynchronous code to speak of in there.


> Today we still see some use of process-level concurrency/parallelism, such as in Postgres.

FWIW, as somebody working on postgres, there's plenty reasons to regret this. The unshared memory, fd spaces make some things more complicated / heavyweight. We've cross-process shared memory allocators, but then the pointers all have to be relative. It's harder to separate connections from a "query execution context", making connections more heavyweight than necessary. Worker threads for async IO - which we'd love to have - would need to be duplicated in each process. Etc.

There's still quite some benefits, like increased robustness in the face of bugs, reduced contention for memory alloccators etc, ... But I doubt you'd find anything close to a majority inside the postgres team to use threads if we'd need to make the decision again, unencumbered by existing code.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: