in reply to RFC: Using 'threads' common aspects

A couple of questions.


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.

Replies are listed 'Best First'.
Re^2: RFC: Using 'threads' common aspects
by DeadPoet (Scribe) on Jan 08, 2011 at 15:19 UTC
    I am presuming that you are referring to the independent threads that manage the print_manager and the thread_timer aspect of the program. Yes, those threads are outside of the pool and are started near the top of MAIN.
    my $thr_pm = threads->create( \&print_manager )->detach(); my $thr_tm = threads->create( \&thread_timer )->detach();
    However, the worker aspect of the program operates from a pool of threads, which are reused and defined by:
    for ( 1..$DEFAULTS->{'max_threads'} ) { my $q_work = Thread::Queue->new(); my $thr = threads->create( \&thread_worker, $q_work ); $work_queues{$thr->tid()} = $q_work; } ## end for max_threads.
    I am expecting the ':locked' attribute to ensure that no other thread, intentional or otherwise, will access the subroutine while the active thread has control. Do you read otherwise? If so, how?
      I am expecting the ':locked' attribute to ensure that no other thread, intentional or otherwise, will access the subroutine while the active thread has control.

      If you read the threads documentation, the :locked attribute isn't mentioned because it does nothing. Quite literally nothing. It is a noop.

      It is non-functioning leftover from perl5005 threads that has never had any affect on iThreads.

      I am presuming that you are referring to the independent threads that manage the print_manager and the thread_timer aspect of the program.

      No. Having a couple of other threads outside of the worker pool isn't a problem. That's quite normal.

      The problem is that you manage each of the threads in your 'pool' as individual entities. Ie. Each has a separate queue. Which means that your dispatcher has to allocate and coordinate work to each worker individually. The result of which is the excessive complexity of your implementation. With a traditional thread pool, all the threads are identical and often anonymous. And they get their work from a single work queue.

      Think of this as analogous to the baggage carousels in airports. The bags are loaded onto the belt back-of-house, and the 'workers', passengers in this scenario, collect the bags from the carousel entirely independently of each other, and of the loading.

      What you've done is to replace the carousel with a fan of one-to-one conveyors, and placed a dispatcher between the inbound conveyor and that fan. He has to take the bags off the inbound conveyor, read the labels, and decide which of the fan of conveyors he needs to place each bag on for it to get to the appropriate customer.

      You've added huge complexity--the fan of one-customer-at-a-time, one-bag-at-a-time conveyors; and created a bottle-neck--the dispatcher--upon whom all the customers have to wait. Not to mention all the tagging, control and coordination problems created by the need to route each customer to the right conveyor and each bag to the right customer.

      In the process, you've made some very strange choices.

      For example, your 'jobs' queue. You create a shared array, onto which you push all your jobs en-mass. You then pull them off that queue and feed them onto the worker's individual queues. But it is the same thread that puts them on the jobs queue as takes them off. So there was no need for a shared data-structure--with all the size and performance penalties it entails. A simple array would have sufficed.

      And the rest of your code is full of similar anomalies.

      I'm trying very hard not to be negative of someone trying to do what I have declined to do, but the truth is that as a tutorial, your code is actually worse than no tutorial, because it teaches a lot of bad practices. And once out there, they become very hard to unlearn, and the time-bombs they will create become very hard to diffuse.

      Given the (unwritten, despite your original claim to "solid documentation") 'spec' of your 400+ line program, its function (such as it is) can be easily and far, far more clearly achieved with 30 or 40 lines, of cleaner, clearer and more easily maintained code. It is typical of code written to "demonstrate some functionality" rather than solve a problem. It is also typical of a program written by someone who has yet to try and use iThreads in a real application.

      Sorry.


      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.
        There is no need at all to be sorry. This is exactly why I placed this as an RFC. While your points simply enforces why I feel a solid illustration of threads is needed. Moreover, I agree that this example may not be it, but at least the topic is raised.

        Next, many will say just use module X or module Y to solve this or that thread problem. However, did one really learn how to do it, or did they just learn a shortcut that they may not have in the future? Me, I prefer to learn and understand.

        Finally, I have great respect for your comments and thoughts, as I see you have actually authored several write-ups. While others tend never to pass knowledge on and consistently stand in judgement of those that would. So, no apologies are needed. --Poet
        Okay, let me back this off a bit and see if I can't get this correct. For now, I have dropped the timers and I "think" I have made the corrections that you have stated. However, I am not 100% and would appreciate your eyes.

        If there are glaring errors, then please provide insight as to what I have done wrong.