2

I want to pause the execution of while loop for 200 milliseconds.I have used [NSThread sleepForTimeInterval:0.2] ,It's working fine for me but, I want to know what are the alternative ways to pause execution of while loop?

boopathy
  • 427
  • 2
  • 9
  • 20
  • 2
    Is this the main thread? (please reply with "no"). – trojanfoe Feb 20 '14 at 10:34
  • No,It's run in the separate thread. – boopathy Feb 20 '14 at 10:36
  • Phew. But this answer cannot be resolved without knowing *why* you are pausing. There is almost certainly a better way to achieve what you want, I suspect. – trojanfoe Feb 20 '14 at 10:38
  • I don't see the point of that code. Are you just testing something? – trojanfoe Feb 20 '14 at 10:46
  • `while(true){` `NSLog(@"before sleep");` `NSDate *date=[NSDate date];` `NSTimeInterval ms = [date timeIntervalSince1970];` `[NSThread sleepForTimeInterval:0.2];` `NSLog(@"After sleep");` `date=[NSDate date];` `NSTimeInterval ms1 = [date timeIntervalSince1970];` `NSLog(@"sleep time duration : %f",ms1-ms);` `}` – boopathy Feb 20 '14 at 10:50

2 Answers2

1

If it's working fine then no problem, however if you are doing something in the thread that needs the runloop (i.e. NSTimer or NSURLRequest in async mode) then you need to run the runloop, so this would be required:

(tested)

+ (void)runRunLoopForTimeInterval:(NSTimeInterval)timeInterval {
    NSDate *stopTime = [NSDate dateWithTimeIntervalSinceNow:timeInterval];
    while ([stopTime compare:[NSDate date]] == NSOrderedDescending) { 
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                 beforeDate:stopTime];
    }
}

and call it like this:

[SomeClass runRunLoopForTimeInterval:0.2];

EDIT Some assumptions:

  1. The thread is a background thread.
  2. You are waiting for something to happen. If so you can use something like RunLoopController which allows that condition to be signalled and will force the run loop to break out before the required time.
trojanfoe
  • 120,358
  • 21
  • 212
  • 242
  • This what you might want to do, but _why_ do you want to sleep for 200ms? – Oliver Atkinson Feb 20 '14 at 10:55
  • @OliverAtkinson You might be waiting for something else to happen. In which case the code given would need to check for that condition as well (better still that condition should be signalled with something like a Mach Port that breaks out of the run loop; see https://github.com/trojanfoe/RunLoopController). – trojanfoe Feb 20 '14 at 10:56
  • would the better option not be to block the thread but use GCD? I don't know the exact use case for the OP so its difficult to say but its rarely a good idea to want to sleep. – Oliver Atkinson Feb 20 '14 at 11:00
  • @OliverAtkinson Not if you are using `NSTimer` or async `NSURLRequest` in that thread, no. My answer is specifically for a use-case where the runloop is required to run. – trojanfoe Feb 20 '14 at 11:01
  • I am going to write screen capture code.The screen should be happen in every 200 milliseconds interval. `while(true){` `NSLog(@"before sleep"); ` `NSDate *date=[NSDate date];` `NSTimeInterval ms = [date timeIntervalSince1970];` `[NSThread sleepForTimeInterval:0.2];` `//calling screen capture method `NSLog(@"After sleep");` `date=[NSDate date];` `NSTimeInterval ms1 = [date timeIntervalSince1970];` `NSLog(@"sleep time duration : %f",ms1-ms); }` – boopathy Feb 20 '14 at 11:10
  • @boopathy In that case my answer doesn't address you directly, but stands for others, who want their thread to sleep, and need the runloop to work. – trojanfoe Feb 20 '14 at 11:14
  • After 2 minutes execution of the above code ,The NSthread sleepForTimeInterval time taken has been increased automatically.why?what is the problem in the above code? – boopathy Feb 20 '14 at 11:17
  • It's probably broken. I'll test it and get back to you. – trojanfoe Feb 20 '14 at 11:18
  • @trojanfoe makes sense for that use case, I guess I was just skeptical of the OP's need for the sleep as it wasn't clear from the original question. – Oliver Atkinson Feb 20 '14 at 11:32
  • @OliverAtkinson You need to direct your question to him then. – trojanfoe Feb 20 '14 at 11:36
  • @boopathy OK, I've fixed the code (`timeIntervalSinceNow` returns a negative value so you need to add it to `timeInterval`). However you don't need to use my code at all if you don't have runloop-related activities in the thread. – trojanfoe Feb 20 '14 at 11:40
  • @boopathy OK, fixed it properly this time. Here is the test: https://gist.github.com/trojanfoe/9111894 – trojanfoe Feb 20 '14 at 11:50
  • I am running a multithreaded program. One thread(not the main thread) captures the screen continuously every 200ms and write the data to a TCP socket. Another thread will listen for incoming data in the TCP socket. I assume, the problem is caused when I call [NSThread sleepForTimeInterval:0.2], some other thread starts running and it doesn't finish its work before the 200 ms. How do I know which Thread is currently running? In other words, when the code stays in [NSThread sleepForTimeInterval:] I want to know the current code(with Class Name/Line number) that is being executed? – boopathy Feb 24 '14 at 09:36
  • @boopathy The kernel decides thread prioritization and scheduling so this cannot be determined from userland, other than adding logging to your own code so you can see which thread ran, and when. – trojanfoe Feb 24 '14 at 10:08
0

Let's imagine we have a while in the following form:

while (... condition ...) {
   ... doSomething ...;

   if (... waitCondition ...) {
      //I want to wait here
   }
}

We will make it asynchronous, first by abstracting things into methods:

- (BOOL)condition {
   //some condition, e.g.
   return (self.counter > 5000);
 }

- (void)doSomething {
   //do something, e.g.
   self.view.alpha = self.counter / 5000.0f;
   self.counter++;
}

- (BOOL)waitCondition {
   // some wait condition, e.g.
   return ((self.counter % 100) == 0);
}

- (void)startWhile {
   //init the state
   self.counter = 0;
   [self performWhile];
}

- (void)performWhile {
   while ([self condition]) {
      [self doSomething];

      if ([self waitCondition]) {
         [self performSelector:@selector(performWhile)
                    withObject:nil
                    afterDelay:0.2
                       inModes:@[NSDefaultRunLoopMode]];
      }
   }
}

Instead of using a global state in self, you can also use a parameter with performWhile.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • My while loop should be in the following condition `while(**** condition *****)` `{` `//do something` `//wait here for 200 milliseconds` `//do something` `}` – boopathy Feb 20 '14 at 13:14
  • `while(true){ ` `NSLog(@"before sleep"); ` `NSDate *date=[NSDate date]; ` `NSTimeInterval ms = [date timeIntervalSince1970]; ` `[NSThread sleepForTimeInterval:0.2]; ` `//calling screen capture method ` `NSLog(@"After sleep");` `date=[NSDate date]; ` `NSTimeInterval ms1 = [date timeIntervalSince1970]; ` `NSLog(@"sleep time duration : %f",ms1-ms); }` this is my while loop.After 2 minutes execution of this while loop ,The NSthread sleepForTimeInterval time taken has been increased automatically.why?what is the problem in the above code? – boopathy Feb 20 '14 at 13:45
  • @boopathy What you have is not really a while loop and you shouldn't use one then. Use a `NSTimer` as @trojanfoe suggests. – Sulthan Feb 20 '14 at 14:29