in reply to Why does threads::join block SIGALRM

See Safe signals for some background to what you've been told elsewhere.

That said, setting PERL_SIGNALS=unsafe won't change anything; and least not on windows. You'll need to try it for yourself on other OSs.

However, the bottom line here is that using an alarm to interrupt join() is a pretty weird thing to want to be doing. If you outline the use-case; there is almost certainly a simpler and more reliable solution.


With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
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". I knew I was on the right track :)
In the absence of evidence, opinion is indistinguishable from prejudice. Not understood.
  • Comment on Re: Why does threads::join block SIGALRM

Replies are listed 'Best First'.
Re^2: Why does threads::join block SIGALRM
by CDahn (Novice) on Jun 07, 2016 at 02:50 UTC

    Agreed, unsafe signals aren't required. I definitely agree that refactoring this code may be the order of the day. The person was attempting to identify when worker threads which were told to finish up work, didn't finish up and a forceful exit occurs. Consider it to be like deadlock avoidance.

    I boiled it down to a brain dead example to try and isolate exactly what was going wrong in the code, and ultimately determined it was the join() call. I created the equivalent C code, and found that pthread_join() doesn't block deliver of the SIGALRM. So, assuming that's actually what threads::join() is using (the guy over at SO realized he misspoke saying it was implemented with mutex_lock()), then it seems like I should get the same behavior out of perl. But, I'm assuming there's something with how signals are being delivered, or the layer of indirection in the interpreter calling out to pthread_join() that prevents the signal from being delivered in perl, where it is in C.

      I created the equivalent C code, and found that pthread_join() doesn't block deliver of the SIGALRM.

      The existence of SAFE_SIGNALS in perl means that nothing you do in C is "equivalent"; and no lessons drawn from C can be applied to Perl threads.

      It is also unfortunate that when Perl's threads were devised, the authors chose the pthreads api as their base, as that entire api is full of holes, anomalies and sheer bloody-minded justifictions.

      For example: a useful pattern of thread usage is a fixed sized thread pool that starts a fixed number of threads doing work, and then replaces the first one to finish with another doing the next unit of work. To enable this, it would be useful to be able to issue a 'block-and-join-the-next-thread-that-finishes()' call; the logical equivalent of:

      waitpid(-1, &status, 0);

      But the pthreads api docs obnoxiously state:

      There is no pthreads analog of waitpid(-1, &status, 0), that is, "join with any terminated thread". If you believe you need this functionality, you probably need to rethink your application design.

      It's also unfortunate that development of the Perl api hasn't attempted to keep pace with the later revisions of the underlying pthreads api.

      For example: If the pthreads api: int pthread_timedjoin_np(pthread_t thread, void **retval, const struct timespec *abstime); was exposed as a part of the Perl threads api, then it would go a long way to addressing your particular problem; and would permit several useful design patterns that are currently either impossible, or require elaborate hand-coding by the user to implement.

      The history of threading in Perl is one fraught with short-sighted decisions and prejudices. 10 years ago I wrote The future is threaded which basically got the response: "thread is spelt 'fork'" from many directions.

      I'm currently working on speeding up an elaborate piece of scientific C++ code, trying to reduce the run times from 90+ hours by an order of magnitude. I can get over one third of that reduction by simply splitting the major loops across my 4 cores threads. Another 3rd will come from hand-coding the strip-mining, loop-blocking and swizzling needed to use SSE vector operations on the code; which is tedious and laborious. The last third will have to come from careful hand-optimisations and dropping into assembler.

      My old 4 core machine has seen better days; almost nothing of the original machine remains and even those parts that I've already replaced -- like the cpu fan -- are beginning to wear out. Long story short, I'm currently specing up a replacement machine based around an 8-core 4Ghz processor for £130; and if I could bring myself to paying through the nose for it I could be looking at a 20(10) core processor.

      With the latter machine, I could achieve the full order of magnitude time saving just by adjusting the number of threads.

      10 years on, that threaded future is now; and Perl hasn't moved forward at all. So sad.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      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". I knew I was on the right track :)
      In the absence of evidence, opinion is indistinguishable from prejudice. Not understood.
        BrowserUK, thanks for that insight, that was exactly what I was looking for. I tried out PERL_SIGNALS=unsafe, and it did indeed cause the behavior to be what I was expecting, threads::join() is now "interrupted", exactly like pthread_join(). That being said, that's clearly a terrible idea in the long run, so I've refactored the code accordingly.
      I should also note that after a lively discussion, it's probably not accurate for me to say that pthread_join() is "interruptable", as the man page doesn't claim that it can be, technically, interrupted (returning EINTR). That being said, it can't be disputed that the C program is "suspending" the pthread_join(), or something, in order to call the ALRM signal handler, and then goes back to waiting in the pthread_join().