Elijah has asked for the wisdom of the Perl Monks concerning the following question:

I have noticed a few times that doing a check for time in a while loop and waiting for the time to exceed a predetermined amount of seconds to pass before performing a certain task that sometimes the task is never performed because the conditional statement is never satisfied.

For example:

my $thread = threads->create("detached_thread"); $_->join for threads->list; sub detached_thread { my $endtime = (time+1800); while (1) { if (time >= $endtime) { print "30 minutes have passed!\n"; exit(0); } } }
In this example I use a while (1) loop but in the real app the while (1) is a while (my $data = <$sock>).

Has anyone else ran across this issue? If so what is the deal with it?

Replies are listed 'Best First'.
Re: Issue with time() in loop?
by Tanktalus (Canon) on Nov 13, 2005 at 15:41 UTC

    Is there actually any data coming in on your $sock? Is the $sock set to blocking mode? If you're blocked, and there is no data, the OS will wait forever. You're better off using select (or IO::Select) to give a timeout to your waiting. Then you won't need time, either.

      Tanktalus is most likely right. If you are not sure how often and how much data will be sent to your thread, you should really do something like

      use IO::Select; my $s = IO::Select->new(); $s->add(\*FILE); my @ready = $s->can_read(1800); # 60*30 seconds = 30 minutes foreach (@ready) { # read your handle }
      Updated: Thanks to Tanktalus for pointing out a few typos.
      Yes there is constantly data on the socket. I know this by printing it to screen when it comes through. Even if there was not it is a non blocking socket.

      Maybe the example I gave was not a very good representation. It seems that most of the replys are focusing on the socket and the thread when these are more than likely not the issue. I am using threads because that is what my application calls for. IO::Select would not be the best choice in my case because there are thousands of lines of code a second coming across more than 100 socket connections simultaneously. I chose the method I did because of what my app does.

      It was also suggested to use the timeout feature of IO::Select, this would also not be what I want becasue I want the function to be executed after a set amount of time no matter if the socket is receiving data or not. It was also asked if I know this is happening becasue I wait 25 minutes? Well actually no, I know it is happening because I wait two or three hours when it is suppose to happen after 30 minutes and it never does. I also use threads because in the real application I detach this thread so it monitors the time and only the time independant of anything else that is going on in the application.

      I know not all of this applies to your post Tanktalus, but I just wanted to reply to everyones questions so far in one place. Maybe this will give a better idea of what is going on?

      Edit: I also forgot to mention that my original question was a bit misleeding. The detached thread I use to check the time does use a simple while (1) loop. In the application for each thread I also use another while loop monitoring the socket. I kinda mixed those two together.

        Then, I would suggest rethinking your design, if you can. e.g., I hear about POE, perhaps that would be a better way to design to make it easier to debug.

        Even without POE, you could do all this on a single thread using IO::Select. Especially if there's only one CPU anyway, having multiple threads isn't going to make your program go (much) faster. It will be a battle between the overhead of task switching in the kernel (far removed from your app) and the optimisation of that task switching. Otherwise, selecting on your hundred ports will probably be faster and easier to write.

        A distinct possibility in your current problem is that this thread is chewing up so much CPU time that the OS starts to throttle it, and outright ignore it. Try inserting a "sleep(1)" in your loop so that it only checks once per second, rather than as often as the CPU (and OS) allows. Or, better yet, calculate the time difference between now and the desired time, and sleep for that long - which will use zero CPU time until the desired time.

Re: Issue with time() in loop?
by pg (Canon) on Nov 13, 2005 at 19:00 UTC

    Other than what others have already pointed out, I doubt that you need thread. My guess is that the reason you use thread, is to monitor multiple sockets at the same time. A better idea is to use IO::Select.

    The following code demoes this. Just run one instance of the server and two instances of the client. Observe how the server receives messages from both clients without threading.

    Server:

    use strict; use warnings; use IO::Select; use IO::Socket::INET; my $server = IO::Socket::INET->new(Proto => "tcp", LocalAddr => "local +host", LocalPort => 3000, Listen => 10); my $selector = IO::Select->new(); { my $connection = $server->accept(); print "First client connected\n"; $selector->add($connection); } { my $connection = $server->accept(); print "Second client connected\n"; $selector->add($connection); } while (1) { for my $reader ($selector->can_read()) { my $line = <$reader>; print $line; } }

    Client:

    use strict; use warnings; use IO::Socket::INET; use IO::Select; my $connection = IO::Socket::INET->new(PeerAddr => "localhost", PeerPo +rt => 3000, Proto => "tcp"); for (1 .. 100) { print $connection "$_\n"; sleep(1); }
Re: Issue with time() in loop?
by Aristotle (Chancellor) on Nov 14, 2005 at 00:11 UTC

    From MJD’s file of good advice:

    #11943 Ah yes, and you are the first person to have noticed this bug since 1987. Sure.

    Throw a bunch of prints or warns all over your code to find the precise position at which execution hangs, and when you know where it is, come back and tell us.

    In all likelihood, the following good advice applies to your hunch about time:

    #11950 Now you are just being superstitious.

    Makeshifts last the longest.

      It appears that all of you have missed my question in my original post.

      Has anyone else ran across this issue? If so what is the deal with it?

      I am not stating anything. I merely asked a simple question, if anoyne has ever noticed any issues when checking against time in a loop using threads. No it does not happen all the time which is why I am asking. If it was as easy as a static bug there would be no need in even coming here. I have suspected an issue with threads since I first noticed this. I thought I may get some valid info from someone else if they had ever seen this before which is why I included the threads in the example so you all would know the usage and the indication. But for this I get 3 or more threads saying I don't need to use threads and a few more telling me to use IO::Select and more blaming the socket. None of them addressed my original question.

      Not flaming anyone for trying to help but it is apparent most of you are used to feeling like Gods among idiots and approach your replies as such.

      Throw a bunch of prints or warns all over your code to find the precise position at which execution hangs, and when you know where it is, come back and tell us.

      Now why didn't I think of that? Why would I need to come back and tell you anything after I find out what the issue is? Are you implying I am not capable of fixing it myself? Now go ahead and spout off about how my post was lacking of any information that would allow you to help me at all. I so enjoy seeing this excuse plastered all over this site when peoaple do not understand what they are trying to help with. Better yet tell me how my lack of intelligence is why I would not be able to fix this myself. Then tell me you know just how stupid I am because I could not make you understand my simple question and how you know all about me from a single post.

      I haven't had a good downvoting in a while. Thanks for the effort.

        I’ve had 10,000 weird inexplicable bugs like this one, and every single time it was due to my own code. Whether that makes me a god among idiots is your call.

        Makeshifts last the longest.

        The difference between a "God" and an "idiot" is that a "God" assumes the problem is his/her own code, while the idiot, well, assumes the tools.

        That's not to say the God is always right nor the idiot always wrong. But, with no evidence to the contrary, everyone here is going to assume it's your code, not your tool (perl). Post a working, testable, reproducable, standalone piece of code that shows the problem, and one of three things will happen: a) you'll find the bug yourself (this happens to me quite often - once I found my bug, then found another problem which I then posted, having a small testcase to show - and, again, if memory serves, it was me.), b) we'll show your bug (or maybe just misunderstanding or maybe just quirk that you're not following), or c) we'll confirm it's a real, live bug in the perl core. With a number of P5Porters here, you may find it fixed soon, too.

        Why would I need to come back and tell you anything after I find out what the issue is?

        I like pigeonholing people. So here we go again. You may need to come back to us because you don't understand why something is happening - it looks right to you, so you want some extra eyes looking at it. Or you may be the type who needs help to decipher what you've just done. Personally, I think that just coming up with a reproducable, standalone script for dissection is sufficient - I'm not sure why Aristotle wants more than that.

        Now go ahead and spout off about how my post was lacking of any information that would allow you to help me at all.

        I'm a results-oriented kind of guy. And I need to ask, "How's that working for you?" I mean, based solely on results, the question you posed, with the information contained therein, obviously didn't help. There are two conclusions I can draw off the top of my head (feel free to add more): a) we're all idiots, or b) you didn't provide the information that we needed in order to see and help with (or perhaps solve) your problem. Which do you find more reasonable?

        Alternately, if it had been obvious to us that we did "not understand what [we] are trying to help with," we could have simply ignored your post, and you would have received absolutely zero feedback. Then you would be grumbling that no one could help you. Wouldn't you rather that we made an honest effort (remembering how much you're paying for this help) to give you feedback that perhaps your question wasn't clear enough?

        Then tell me you know just how stupid I am because I could not make you understand my simple question and how you know all about me from a single post.

        Here's a simple question: "What do I have in my pocket?" Gollum didn't think it so simple, either. The problem is that the question is, indeed, simple. But that's a superficial simpleness which belies a whole host of complexities. Such as "Where has the hobbitsses been, my precious?" In your case, we need more information because we can't reproduce your problem. All we can do is throw out guesses - which we have - and hope they help.

        I haven't had a good downvoting in a while.

        Getting snarky at free help doesn't help. You get what you pay for. And if I were your tutor or other paid help, I'd demand seeing the full, reproducable code. I demand that much of those who work for and with me (where I'm paid to help). And even my friends who have taken programming and get stuck (whether it's perl, shell, C++, Java, or languages I don't even know, such as .NET) know that they need to zip up their entire source code and email it to me so I can see their problem. Describing their problem over the phone just simply doesn't work reliably.

        I, like most monks here, don't mind helping. But you need to be a willing spirit in this and help us help you.

Re: Issue with time() in loop?
by BrowserUk (Patriarch) on Nov 13, 2005 at 21:17 UTC

    Showing "examples code" that cannot be run, and does not show the details (for example that your thread is non-blocking), make any and all answers just speculation.

    Reduce your program to runnable code that demonstrates the problem, and you'll probably get a solution.

    One thing I can suggest is that using exit() to terminate a thread is a very bad idea.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Well exit probably should have been return or something else but as I said it was a simple example.

      Everyone seems to be suggesting work-arounds which is not what I was looking for. I can come up with numerous ways to make it work as I have already done but was more interested in the fact that there seems to be an issue with time() in a loop. I currently only check every 30 seconds so checking it too often should not be the issue. I was just wondering if anyone else had ever experienced this.

      The background of my application was just history on how I came across this problem. I was not really asking for help with my application so posting a stripped down version would do me no good. Thanks to all for their suuggestions.

        Basically, your post doesn't contain a testable sample, nor enough information to construct one, nor even enough to relate your perception of a problem with other bug reports. And in their absence, it is hard to see how time() would be failing.

      • Does it always fail, or only occasionally?
      • Have you managed to reproduce the problem in a simple example?
      • If you have, does it still fail if you run the failing code in a non-threaded script?

        In all honestly, it really seems more likely that the socket you are reading from stops receiving because the other end diconnected, or the socket froze, or you are running so many threads that one of them simply didn't get scheduled regularly enough.

        Thinking abstractly, it's possible that there is some buffer somewhere in perl that is used when fetching the time from OS, that might not be completely thread-safe, though I have never seen any similar effect and I've used time() in conjunction with threads a lot. Which OS are you running on?


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        Here's the problem. You're stating that Perl's time function doesn't work in a loop. If that's true you should be able to post a small test program that illustrates this. For example, the following program does not use threads or sockets but relies on time() to terminate after 30 seconds:
        #!perl use strict; use warnings; my $endtime = time + 30; while (1) { if (time > $endtime) { print "30 seconds have passed\n"; exit; } sleep 1; }
        and lo and behold, it works.
Re: Issue with time() in loop?
by vek (Prior) on Nov 13, 2005 at 17:49 UTC

    Tanktalus has offered a very sensible suggetion. In case you want to persue another alternative with the code you have, you could trigger & catch a $SIG{ALRM} via alarm after your $endtime seconds threshold has been met.

    -- vek --
Re: Issue with time() in loop?
by Anonymous Monk on Nov 13, 2005 at 15:47 UTC
    How did you notice this? By waiting 25 minutes?