http://qs321.pair.com?node_id=426675


in reply to Re^5: Isolating dynamically loaded modules with Thread::Isolate.
in thread Isolating dynamically loaded modules with Thread::Isolate.

You have indeed demonstrated conclusively that in absence of better choices, iThreads are useful.

I stand by my assertion that threads are only useful in the absence of fork(), and that this would be even more starkly obvious if there were just slightly better IPC mechanisms than those invented decades ago.

I do also stand by polemically expressed assertion that a lock of fork() makes for an amputated platform, which is underpinned by the fact that proponents of such platforms usually like threads because they make it easier to coordinate parallelly executing pieces of code.

If you feel compelled to counter positions you disagree with and decide to act on it, how does it reflect on you to tell someone else who is doing the exact same to “quit dogging” you? I happen to partially disagree with a number of positions you've defended recently; and you happen to often defend your positions ardently. I'd react just the same if someone else was arguing the same positions.

To expound on the point in case it isn't clear what my argument is: the key semantic that makes fork() so useful is that it allows inheriting the current execution environment to the child. This is the facility which threads restore on a CreateProcess()/spawn() platform. I don't think anyone can reasonably argue that this facility is not incredibly useful. Server daemons on Unix are traditionally implemented with fork(); on Windows, they use threads: in both cases, for this exact reason. And that brings me the point: when there's a way to do that between processes, there's no need to invent a duplicate, less safe mechanism for parallel execution outside processes.

Hopefully you can accept that as a clearly stated position (rather than just arguing for argument's sake), regardless of whether you agree with it (I have no illusions about that :-)).

Makeshifts last the longest.

Replies are listed 'Best First'.
Re^7: Isolating dynamically loaded modules with Thread::Isolate.
by BrowserUk (Patriarch) on Jan 31, 2005 at 19:47 UTC

    The problem is that you insist upon taking a specific subject--on-topic in context of both the site and the thread--and injecting a generalised statement, based more upon prejudice and dogma, than reasoned argument, and stating your position in those terms.

    It does nothing to further the original discussion and serves only to provide a platform on which you can expound in the sure knowledge that your pro-unix, "windows is broken" stance will play to the gallery.

    An example;

    ...the key semantic that makes fork() so useful is that it allows inheriting the current execution environment to the child.

    This is a circular argument. With threads, you don't need to "inherit the current execution environment"--you already have it! Each thread is a complete execution enviroment. It can choose to be completely isolated and independant, or share exactly that which needs to be shared.

    The primary flaw in perl threads is that they attempt to emulate the fork mechanism in order to make fork & exec style idioms portable to the windows platform. The very thing that makes iThreads accusable of being "slow and memory hungry" is the that they insist upon attempting to duplicate the fork behaviour by replicating everything that exists at the point of spawn.

    Indeed, from my less than perfect historical view, this exactly how they came about. It's not that there is anything wrong with the fork behaviour where that is the "natural order of things"--it just doesn't work well where the OS does not support it natively. Laudible though portability is, it will always be a compromise.

    And it is unnecessary. If each thread was simply a clean, separate interpeter running in it's own thread in isolation of the others; with no "default" replication of anything; with only that which the programmer chose to share being shared; all of the problems would be completely negated.

    In this schema, shared data (and even objects) would exist in a single (hidden) thread. Accessing those shared entities from other threads would be transparent (via queued requests hidden behind tie's) from the user thread to the sharing thread. The tie/shared mechanism would perform all of the synchronisation and locking. The programmer would simple declare the shared entities as shared and use them, and everything else would be transparent.

    But that has as much relevance to anyone needing multitasking with bidirectional communications today as "slightly better IPC mechanisms than those invented decades ago"--none!


    Examine what is said, not who speaks.
    Silence betokens consent.
    Love the truth but pardon error.

      ...the key semantic that makes fork() so useful is that it allows inheriting the current execution environment to the child.

      This is a circular argument. With threads, you don't need to "inherit the current execution environment"--you already have it!

      That's not the point. Ignore the choice of “inherit” per se; that is purely wording. I'll try to state it more neutrally yet:

      You want to be able to launch a new branch of parallel execution at some point in the program and you want both branches to start out with the same environment and state. You can just do that with processes when you have fork(); you need threads when you don't.

      Makeshifts last the longest.

        ...and you want both branches to start out with the same environment and state...

        Of course fork does that, because that's what fork does. Not all, if fact a very large number of multi-tasking problems don't require those semantics...but with fork, you get them whether you like it or not.

        To back that statement up, the whole "fork & exec" idiom is my proof. You replicate the environment--and then discard all but a minor part of it.

        Many fork and exec programs have to leap through hoops to discard that inherited environment. Just look at the double "fork and exec" shanigans that is required to create a daemon?

        But leaving that aside.

        You can just do that with processes when you have fork(); you need threads when you don't.

        You are still viewing this entirely from the "You only need threads because you haven't got fork" view.

        Turn that around and you get the perspective of "We don't need fork because we have threads!".

        We can argue about which is the better--most flexible, efficient, resource-freindly, programmer friendly etc. etc.--until we are blue in the face, but we were not there when Gordon Letwin et al made their choice.

        At the point in history when that decision was made, replicating processes, even under unix, meant replicating the entire process, code, data, sheduler slots--everything--whereas threads allowed all the code and either some, none or all the data, to be shared.

        The advent of COW clawed back a lot of ground--in some cases, it surpasses it. Perl is one of those cases. The significant thing about Perl in this regard is the way data becomes code, and the segregation between those two becomes blurred, because what is code in the Perl sense, is just data in the terms of the underlying C code.

        But the main point is that threads are not a lesser substitute for fork--they are an alternative approach to solving similar problems. For some applications the fork approach lends itself directly, for others threads are a better fit. Neither is superior or inferior, they are just different. Each has their pros and cons.

        Where Perl and threads fall down, is the attempt to use one as a direct substitute--an emulation--of the other, in an attempt to achieve cross-platform portability. A laudible aim and a heroic effort, but fork isn't the only thing that is done differently on Win32--vis. signals-v-events--and the emulation of signals never quite made it far enough to make the fork emulation compatible, with the fork method of operation.

        And in the process of creating iThreads, an, at best, rather limited API was chosen as the model, which means on Win32, it discards about 70% of the native threads functionality and effectively emasculates them. So, here I sit with a barely usable fork emulation *and* severely restricted access to the very usable, very powerful native alternative.

        Whereas you sit there, with a fully functional, efficient fork, and threads that, whilst written to a API native to your platform, you'll probably never use because you don't need them.

        Though I think if threads did not try to emulate fork, and operated in a more programmer-driven and controllable fashion, then they would be lighter, less memory hungry, more convenient to use and would truely avail the Perl programmer of the benefits of threading--for those applications where they are desirable.

        And were that the case, you might be more inclined to consider the possibility of using them.


        Examine what is said, not who speaks.
        Silence betokens consent.
        Love the truth but pardon error.