First. Before entering the fray; thank you for your reasoned responses.
I do understand your attempts to reconcile disparate interpretations of terms. But, if the world and his dog are allowed to misappropriate terminology to mean whatever they decide it should mean, then we'll end up with having to qualify every use; (" ... threads(Lehman'2007) ... threads(Wikipedia'1995) ... threads(SomoneElse'someOtherTime) ...". I hope every one can see how nonsensical that would become.
For a pretty definitive history of both the term and the concept, seeThe history of threads.
And if you read it all carefully you arrive at the widely accepted definition: In computer science, a thread of execution is the smallest unit of processing that can be scheduled by an operating system.
I am fully aware that the last four words of that sentence contradicts my acceptance of the term threads to describe the concurrency in Erlang despite its operating in user-space. But I believe that is justifiable, at least since 2006, and I'll attempt to do that by contrasting its properties with those of Coro.
Coro implements its own scheduler. ... I still do not understand why coros created by Coro are not user-space threads in your terminology?
Cooperative scheduling is an oxymoron. Like cooperative management or cooperative teenager :)
Coro may call its dispatcher, a "scheduler", but it's Just Another Misnomer™. To put the term 'scheduler' into context, think about other things that keep schedules. Neither trains, buses nor planes wait for their passengers to turn up. On the other hand, taxis are dispatched at the passenger's convenience.
The distinction that sets Erlang's user-space scheduler apart is that (since 2006), a) it scales across SMP cores; b) if one context of execution (CoE) hangs, it doesn't stop others from progressing.
Coro can do neither of these things. Hence why Coro's coros don't qualify as threads.
Are fibers threads?
No. Despite that they may start out as threads. The distinction is that they are not scheduled. A group of fibres may cooperate within the auspices of a single kernel thread, that is itself scheduled. In this way, fibres are distinct and more powerful than coroutines because they a) can scale across SMP cores; b) can coexist and run concurrently with other threads (which in turn may actually be groups of fibres). But still, as with coroutines, if one stops cooperating, the whole group hangs.
Coros can't do this either, so they aren't fibres.
(Though if they would coexist with ithreads, they could become fibres--which would be eminantly useful!)
The fact that perl's ithreads have created a bunch of little pseudo-processes out of the threads!
This is a misinterpretation. Pseudo-forks are created (on win32 only), using the fork keyword. They are nothing to do with the threads module, or the async() function or new() or create() methods of that module. You don't even need to use threads in order to use the pseudo-fork emulation. You just use the fork keyword as on any other platform.
At the C (perl's internals) level, and the OS level, all ithread instances share a single address space. Ithreads are threads, in every sense of that term. They are not processes. They are not pseudo-processes. If you print out $$ from all the threads in a process, you get the same process id. If you kill that process id, you kill all the threads it contains.
I'm not sure I'm convinced how forward-thinking it is to model processes by using threads. "Real" (OS-level) Processes already must explicitly share data. Processes have private data. Processes run their own interpreter. Process run in parallel. Why reinvent the wheel?
Actually, when it comes to pseudo-forks, I agree with you. It was done for one reason only. A (as time has proven, somewhat misbegotten) attempt to make *nix programming paradigms (fork & exec etc.) more easily portable to non-*nix platforms. (Predominantly windows, but also OS/2, and possibly others).
The motivations are good, and the implementation sort of works. But to be properly successful, so many other *nix concepts that are not supported on those other platforms--signals, unix-domain sockets, all-IO-is-files etc.--either cannot, or cannot adequately be emulated, that provision of fork and a very limited signalling capability, do not really help much in porting. They simply move the portability issues elsewhere, whilst adding a whole new bunch of caveats and special cases to be considered.
In the end, it is generally simpler to ignore pseudo-forks and move directly to ithreads which are pretty consistent across all platforms.
But, I suspect that when you said:
I'm not sure I'm convinced how forward-thinking it is to model processes by using threads.
You weren't referring to the little-known and less used pseudo-forks. But were actually talking about the ithreads explicitly-shared-only data model--and likening it to "modelling processes".
When I first came to perl (5.6.1), ithreads were there already. The 5005-threads were also there.
My platform doesn't have fork, and I came from a background that meant that kernel threads had been a part of my daily programming life for 15 or 20 years. So using threads was the most natural thing in the world to me.
When I first read the distinction between the two threading models, 5005-threads everything shared model was far more like I was used to from C/C++/assembler etc. I was never in a position to have any input to the transition from 5005-threads to ithreads, but I remember being somewhat pissed at the prospect of the change.
However, as time has gone on, despite all the limitations of the current implementation, I've come to view the ithreads model as inspired. I'll try to explain why.
Historically, and continuing, the biggest percieved problem with threading--and all forms of shared state concurrency including coroutines--is the accidental sharing of state. It is pernicious because most times it doesn't cause crashes. Just wrong results that are a bitch to track down.
The 'natural' reaction to this problem is to lock everything in sight. But this cure is worse than the disease. It leads to the other head-liners of the anti-shared-state lobby: deadlocking and priority inversions.
Been there, done that, worn out the t-shirts. But here's the thing. In the nearly 10 years I've been programming ithreads, I've never once had a deadlock or a priority inversion. And on the very few occasions I've encountered shared state corruption, it has been the work of seconds to track down and correct.
The reason is that very little state is shared, and when it is, it is explicitly marked as shared.
That simple expedient of having the api/threading model require you to mark shared state with :shared--so simple to do, and yet so powerful in what it achieves in terms of its proactive, prophylactic properties--is (IMO) simply the most useful, usable, powerful addition to the concurrency programmers tool-kit ever. I mean it. Bar none.
It's better than const'ing, immutability, message-passing, and software transactional memory (STM). Individually or all combined. (Note: I'm talking about the ithread concept rather than the current implementation!)
Why? Because it mirrors the way people think. It allows them to intuit about what is shared and what is not. Without adding the duplication costs of immutability; or those plus the paradigm shift of message passing; nor the horrendous uncertainties, increased non-determinisms, and hyper-geometric worst-cases of STM.
The application programmers view of a thread is that it is simply a non-blocking subroutine. It (usually) has a name; some parameters; some local variables, some code that processes those parameters; and a result. (And cleverly, in perl's case, it also has read-only(*) access to outer scopes--closures. Though this may not always be a good thing.)
A view so simple that it takes no effort to intuit about it. It is simply a piece of work that can be delegated to someone else with: "Do this and don't bother me. I'll ask you for the results when I'm ready".
they share data through complex operations akin to IPC
This is a limitation of the implementation, not the concept. It could be improved now as I explained in my previous post.
It could also be improved further than that, in a way that would make it even more intuitive. And such that the performance impact of the thread-enabling of the perl core, on non-threaded code could be severally reduced, if not entirely reversed. I've discussed this at length before and won't reiterate it all here, but in brief. Shared data is, intuitively, global data. And if only global (non-my) data could be shared, then all the internal locking that currently must be applied to my variables--even in non-threaded code--would become unnecessary. Win-win.
So yes. I am quite adamant about my use of terminology--on this subject and many others--because I simply don't think it does anyone any favours at all to conflate terminology. It just confuses and deceives and serves no good purpose. As a UK comedian recently had it: "Describing scourers as "multi-purpose" is simply dishonest. Sure you can scrub many different things with them. But it's still eff'ing scrubbin'!"
Coro; the name says it all. Coroutines are a useful, powerful concept in their own right. But they are not--by any stretch of the imagination--threads. Much less "the only Real threads".
But more to the point. They don't need to advertise themselves as threads. Indeed, if they worked on my platform (and they could), and especially if the worked in conjunction with threads (which they could), then I'd be both using them and promoting them, and thanking the author for providing them.
But, whilst the author continues to devote his POD to making fatuous claims, and enshrining his technical disputes with other respected members of the Perl community, rather than describing it functionality, I'll have no compunction about calling him on it.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.