12

How can I block my thread (maybe process) for nanoseconds or maybe for a milliseconds (at least) period?

Please note that I can't use sleep, because the argument to sleep is always in seconds.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
RajSanpui
  • 11,556
  • 32
  • 79
  • 146
  • 2
    Could you explain why you need such fine-grained waiting? – Jeff Foster Apr 27 '11 at 12:00
  • A way to implement a user-defined timer. – RajSanpui Apr 27 '11 at 12:00
  • 1
    "nanoseconds or may be milliseconds" nano/milli = 1/1.000.000 -- you should be certain which one you want. A nanosecond is roughly 2-3 CPU cycles (assuming 2-3 GHz), so about one or two machine instructions. – Damon Apr 27 '11 at 12:56
  • Well, the mere call to and return from your timer function will take anywhere from two dozen to 500 nanoseconds (in case there is a cache and/or TLB miss). Insofar, finer is not necessarily better, because finer does not mean more precise. The wait/timeout functions offered by the operating system (see answer by R...) are as good as you can _reasonably_ get. Anything finer than that is silly. – Damon Apr 27 '11 at 13:17
  • Possible duplicate of *[Timer function to provide time in nano seconds using C++](http://stackoverflow.com/questions/275004/timer-function-to-provide-time-in-nano-seconds-using-c)*. – Peter Mortensen Jul 14 '15 at 13:24
  • See Stack Overflow question *[Timer function to provide time in nano seconds using C++](http://stackoverflow.com/questions/275004)*. – dubnde Apr 27 '11 at 12:19

7 Answers7

13

nanosleep or clock_nanosleep is the function you should be using (the latter allows you to specify absolute time rather than relative time, and use the monotonic clock or other clocks rather than just the realtime clock, which might run backwards if an operator resets it).

Be aware however that you'll rarely get better than several microseconds in terms of the resolution, and it always rounds up the duration of sleep, rather than rounding down. (Rounding down would generally be impossible anyway since, on most machines, entering and exiting kernelspace takes more than a microsecond.)

Also, if possible I would suggest using a call that blocks waiting for an event rather than sleeping for tiny intervals then polling. For instance, pthread_cond_wait, pthread_cond_timedwait, sem_wait, sem_timedwait, select, read, etc. depending on what task your thread is performing and how it synchronizes with other threads and/or communicates with the outside world.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 1
    Note that for implementing a timer, you probably want `clock_nanosleep` with absolute time (the precomputed next timer expiry time). With relative time, unless you take additional precautions to adjust your sleep intervals based on measured time, you'll accumulate error. – R.. GitHub STOP HELPING ICE Apr 27 '11 at 13:04
  • It's interesting that the clock resolution is said to be at 1e-9 on my computer even though it's just close to impossible to wait for just one nano-second with existing architecture. – Alexis Wilke Oct 12 '20 at 20:58
  • @AlexisWilke: That doesn't mean you can wait for one nanosecond, just that the reported time has significance down to one nanosecond. – R.. GitHub STOP HELPING ICE Oct 12 '20 at 23:35
7

One relatively portable way is to use select() or pselect() with no file descriptors:

void sleep(unsigned long nsec) {
    struct timespec delay = { nsec / 1000000000, nsec % 1000000000 };
    pselect(0, NULL, NULL, NULL, &delay, NULL);
}
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
3

Try usleep(). Yes this wouldn't give you nanosecond precision but microseconds will work => miliseconds too.

Mihran Hovsepyan
  • 10,810
  • 14
  • 61
  • 111
  • Anything to block for nanoseconds? Suppose user gives wait period for: `2.0000045`, this would fail. – RajSanpui Apr 27 '11 at 12:04
  • Even if unix system or other one support nonoseconds it is limited by CPU speed. Let's see why. Consider 2.5 Ghz processor. In one second it can do about 10^8 processor commands this means about 100 operations per microsecond => it is possible handle this granulity on this processor, but 0.1 operation per nanosecond => even if there were support of such granulity the processor can't measure the time correctly. – Mihran Hovsepyan Apr 27 '11 at 12:28
  • 3
    `usleep` was obsoleted in POSIX 2003 and removed in 2008. – R.. GitHub STOP HELPING ICE Apr 27 '11 at 12:30
3

Using any variant of sleep for pthreads, the behaviour is not guaranteed. All the threads can also sleep since the kernel is not aware of the different threads. Hence a solution is required which the pthread library can handle rather than the kernel.

A safer and cleaner solution to use is the pthread_cond_timedwait...

pthread_mutex_t fakeMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t fakeCond = PTHREAD_COND_INITIALIZER;

void mywait(int timeInSec)
{
struct timespec timeToWait;
struct timeval now;
int rt;

gettimeofday(&now,NULL);

timeToWait.tv_sec = now.tv_sec + timeInSec;
timeToWait.tv_nsec = now.tv_usec*1000;

pthread_mutex_lock(&fakeMutex);
rt = pthread_cond_timedwait(&fakeCond, &fakeMutex, &timeToWait);
pthread_mutex_unlock(&fakeMutex);
printf("\nDone\n");
}

void* fun(void* arg)
{
printf("\nIn thread\n");
mywait(5);
}

int main()
{
pthread_t thread;
void *ret;

pthread_create(&thread, NULL, fun, NULL);
pthread_join(thread,&ret);
}

For pthread_cond_timedwait , you need to specify how much time to wait from current time.

Now by the use of the function mywait() only the thread calling it will sleep and not the other pthreads.

Furquan
  • 676
  • 3
  • 5
  • The kernel is very much aware of threads, from the kernel's point of view they are just separate processes that share memory and some other state. – Douglas Leeder Apr 27 '11 at 12:28
  • This answer has wrong information. `sleep` and its variants are for the calling thread, not for the process. However, the idea of using `pthread_cond_wait` rather than a sleep function may be a very good one, especially if the reason for the tiny sleep is to poll some condition. – R.. GitHub STOP HELPING ICE Apr 27 '11 at 12:38
  • @Douglas: kernel is not aware of user level threads, if i am not mistaken. That is why, when one user level thread makes a blocking system call, all user level threads gets blocked. But the same is not applicable for kernel threads. – RajSanpui Apr 28 '11 at 05:49
  • @kingmasher1: You are right. Kernel has knowledge only about the kernel threads. It does not have info about the user-level threads and hence the problem. – Furquan Apr 28 '11 at 06:15
3

nanosleep allows you to specify the accuracy of the sleep down to nano-seconds. However the actual resolution of your sleep is likely to be much larger due to the kernel/CPU limitations.

Douglas Leeder
  • 52,368
  • 9
  • 94
  • 137
2

Accurate nano-second resolution is going to be impossible on a general Linux OS, due to the fact that generally Linux distributions aren't (hard) real-time OSes. If you really need that fined grained control over timing, consider using such an operating system.

Wikipedia has a list of some real-time operating systems here: http://en.wikipedia.org/wiki/RTOS (note that it doesn't say if they are soft or hard real time, so you'll have to do some research).

AVH
  • 11,349
  • 4
  • 34
  • 43
1

On an embedded system with access to multiple hardware timers, create a high-speed clock for your nanosecond or microsecond waits. Create a macro to enable and disable it, and handle your high-resolution processing in the timer interrupt service routine.

If wasting power and busywaiting is not an issue, perform some no-op instructions - but verify that the compiler does not optimize your no-ups out. Try using volatile types.

  • delay loops aren't usable on modern high-performance CPUs (including phones) for anything other than "wait *at least* a few tens of nanoseconds", but possibly 5x to 10x as long depending on CPU frequency being idle vs. max turbo. Also, NOPs don't contribute linearly to delay, except in a loop if you use enough of them to bottleneck on the front-end instead of back-end 1 taken branch per clock. See also [How to calculate time for an asm delay loop on x86 linux?](https://stackoverflow.com/q/49924102) for an RDTSC deadline spin-wait loop. – Peter Cordes Apr 23 '21 at 05:20