next up previous
Next: 如何讓 setuid 的 shell script 可以使用? Up: 自以為已經知道所有答案的人可能會問的高級問題 Previous: 如何用 popen() 對一個 process 做讀寫的動作?

在 C 程式中要怎麼用 sleep() 才能夠 sleep 小於一秒?

首先要注意的是,你只能指定 delay 的「最短」時間;實際上會 delay 多久和 系統的 scheduling 方式有關,例如系統當時的負載。如果你倒楣的話,它還可 能會 delay 蠻長的時間。

並沒有一個標準函式能夠在「小睡」(很短的 sleep)期間提供你計數的功能。 某些系統有提供 usleep(n) 的函式,它能夠暫停執行 n 微秒 (microsecond) 的時間。如果你所使用的系統沒有提供 usleep() 函式,那麼以下有可在 BSD,  System V 使用中的作法。

接下來的這段程式碼是 Doug Gwyn 在 System V 中模擬 4BSD 並利用 4BSD 中的 select() 系統呼叫。Doung 自己都叫它為 'nap()' ;你也可以把它叫做  "usleep()";

	/*
            usleep -- support routine for 4.2BSD system call emulations
            last edit:  29-Oct-1984     D A Gwyn
	*/

      extern int        select();

      int
      usleep( usec )                            /* returns 0 if ok, else -1 */
       	    long                usec;           /* delay in microseconds */
            {
       	    static struct                       /* `timeval' */
               	    {
                    long        tv_sec;         /* seconds */
       	            long        tv_usec;        /* microsecs */
               	    }   delay;          /* _select() timeout */

            delay.tv_sec = usec / 1000000L;
       	    delay.tv_usec = usec % 1000000L;

            return select( 0, (long *)0, (long *)0, (long *)0, &delay );
       	    }

      On System V you might do it this way:

      /*
      subseconds sleeps for System V - or anything that has poll()
      Don Libes, 4/1/1991

      The BSD analog to this function is defined in terms of
      microseconds while poll() is defined in terms of milliseconds.
      For compatibility, this function provides accuracy "over the long
      run" by truncating actual requests to milliseconds and
      accumulating microseconds across calls with the idea that you are
      probably calling it in a tight loop, and that over the long run,
      the error will even out.

      If you aren't calling it in a tight loop, then you almost
      certainly aren't making microsecond-resolution requests anyway,
      in which case you don't care about microseconds.  And if you did,
      you wouldn't be using UNIX anyway because random system
      indigestion (i.e., scheduling) can make mincemeat out of any
      timing code.

      Returns 0 if successful timeout, -1 if unsuccessful.

      */

      #include <poll.h>

      int
      usleep(usec)
      unsigned int usec;                /* microseconds */
      {
            static subtotal = 0;        /* microseconds */
            int msec;                   /* milliseconds */

            /* 'foo' is only here because some versions of 5.3 have
             * a bug where the first argument to poll() is checked
             * for a valid memory address even if the second argument is 0.
             */
            struct pollfd foo;

            subtotal += usec;
            /* if less then 1 msec request, do nothing but remember it */
            if (subtotal < 1000) return(0);
            msec = subtotal/1000;
            subtotal = subtotal%1000;
            return poll(&foo,(unsigned long)0,msec);
      }
在 System V 或其他 非-BSD 的 Unix 中要使用這類的「小睡」程式,可以用  Jon Zeeff 發表在 comp.sources.misc, volume 4 中的 s5nap, 它需要安裝 一個驅動程式,但是裝好後就可以跑得很好。(它的精確度會受到 kernel 中  HZ 這個變數的影響,因為它是用到了 kernel 中的 delay() 函式。)

現在很多較新版本的 Unix 都有提供這類的「小睡」功能了。



Tan Koan-Sin
1999-03-02