มีฟังก์ชันการนอนหลับทางเลือกในหน่วย C ถึงมิลลิวินาทีหรือไม่?


142

ฉันมีซอร์สโค้ดที่คอมไพล์บน Windows ฉันกำลังแปลงให้ทำงานบน Red Hat Linux

ซอร์สโค้ดได้รวม<windows.h>ไฟล์ส่วนหัวไว้และโปรแกรมเมอร์ได้ใช้Sleep()ฟังก์ชันเพื่อรอเป็นระยะเวลามิลลิวินาที สิ่งนี้ใช้ไม่ได้กับ Linux

อย่างไรก็ตามฉันสามารถใช้sleep(seconds)ฟังก์ชันนี้ได้ แต่ใช้จำนวนเต็มเป็นวินาที ฉันไม่ต้องการแปลงมิลลิวินาทีเป็นวินาที มีฟังก์ชันการนอนหลับทางเลือกอื่นที่ฉันสามารถใช้กับการคอมไพล์ gcc บน Linux ได้หรือไม่


sleep(/*seconds*/)ในการ<unistd.h>ทำงาน แต่ถ้าฉันใช้printf("some things")โดยไม่ใช้\nมันจะไม่ทำงาน
EsmaeelE

สำหรับการใช้งานในกรณีนี้เราจะต้องล้างเอาท์พุทที่มี fflush(stdout);หลังจากที่แต่ละprintf()
EsmaeelE

คำตอบ:


184

ใช่ - มาตรฐานPOSIXรุ่นเก่าที่กำหนดไว้usleep()ดังนั้นสิ่งนี้จึงพร้อมใช้งานบน Linux:

   int usleep(useconds_t usec);

คำอธิบาย

ฟังก์ชัน usleep () ระงับการดำเนินการของเธรดการโทรเป็นเวลา (อย่างน้อย) usec microseconds การนอนหลับอาจยาวขึ้นเล็กน้อยจากกิจกรรมของระบบใด ๆ หรือตามเวลาที่ใช้ในการประมวลผลการโทรหรือตามความละเอียดของตัวจับเวลาระบบ

usleep()ใช้เวลาในระดับไมโครวินาทีดังนั้นคุณจะต้องคูณอินพุตด้วย 1,000 เพื่อที่จะเข้าสู่โหมดสลีปในมิลลิวินาที


usleep()ได้เลิกใช้แล้วและต่อมาได้ถูกลบออกจาก POSIX; สำหรับรหัสใหม่nanosleep()เป็นที่ต้องการ:

   #include <time.h>

   int nanosleep(const struct timespec *req, struct timespec *rem);

คำอธิบาย

nanosleep()ระงับการเรียกใช้เธรดการเรียกจนกว่าอย่างน้อยเวลาที่ระบุไว้*reqจะผ่านไปหรือการส่งสัญญาณที่ทริกเกอร์การเรียกใช้ตัวจัดการในเธรดการโทรหรือยุติกระบวนการ

โครงสร้าง timespec ใช้เพื่อระบุช่วงเวลาด้วยความแม่นยำระดับนาโนวินาที กำหนดไว้ดังนี้:

       struct timespec {
           time_t tv_sec;        /* seconds */
           long   tv_nsec;       /* nanoseconds */
       };

msleep()ฟังก์ชั่นตัวอย่างที่ใช้งานโดยใช้nanosleep()การนอนหลับต่อไปหากสัญญาณถูกขัดจังหวะ:

#include <time.h>
#include <errno.h>    

/* msleep(): Sleep for the requested number of milliseconds. */
int msleep(long msec)
{
    struct timespec ts;
    int res;

    if (msec < 0)
    {
        errno = EINVAL;
        return -1;
    }

    ts.tv_sec = msec / 1000;
    ts.tv_nsec = (msec % 1000) * 1000000;

    do {
        res = nanosleep(&ts, &ts);
    } while (res && errno == EINTR);

    return res;
}

23
เหตุใดพวกเขาจึงเลิกใช้ฟังก์ชันง่ายๆสำหรับฟังก์ชันที่ซับซ้อน แทนที่จะใช้สมองในระดับนาโนวินาที () อาจใช้การนอนหลับในขณะนี้

usleep ไม่สามารถทำนาโนวินาทีได้ในขณะที่ nanosleep ควร
muni764

55

คุณสามารถใช้ฟังก์ชันข้ามแพลตฟอร์มนี้:

#ifdef WIN32
#include <windows.h>
#elif _POSIX_C_SOURCE >= 199309L
#include <time.h>   // for nanosleep
#else
#include <unistd.h> // for usleep
#endif

void sleep_ms(int milliseconds){ // cross-platform sleep function
#ifdef WIN32
    Sleep(milliseconds);
#elif _POSIX_C_SOURCE >= 199309L
    struct timespec ts;
    ts.tv_sec = milliseconds / 1000;
    ts.tv_nsec = (milliseconds % 1000) * 1000000;
    nanosleep(&ts, NULL);
#else
    if (milliseconds >= 1000)
      sleep(milliseconds / 1000);
    usleep((milliseconds % 1000) * 1000);
#endif
}

3
เมื่อเราไม่มี_POSIX_C_SOURCE >= 199309Lเช่นในกรณีของ-ansiหรือ-std=c89ฉันขอแนะนำให้ใช้struct timeval tv; tv.tv_sec = milliseconds / 1000; tv.tv_usec = milliseconds % 1000 * 1000; select(0, NULL, NULL, NULL, &tv);แทนusleep(milliseconds * 1000);. เครดิตไปที่นี่
Josh Sanford

ตอบโจทย์มาก! หมายเหตุนี่เป็นnanosleep()เอกสาร: man7.org/linux/man-pages/man2/nanosleep.2.html การโพสต์ลิงก์เอกสารสำหรับฟังก์ชันเฉพาะแต่ละแพลตฟอร์มที่ใช้ที่นี่จะเป็นประโยชน์
Gabriel Staples

โปรดทราบว่าเมื่อคอมไพล์กับgcc -Wall -g3 -std=c11 -o sleep_test sleep_test.c && ./sleep_testบน Linux Ubuntu ด้วย gcc เวอร์ชัน 4.8.4 ฉันจะได้รับคำเตือนต่อไปนี้: warning: implicit declaration of function ‘usleep’ [-Wimplicit-function-declaration]. การแก้ปัญหาคือการเพิ่มต่อไปนี้ 2 กำหนดไปด้านบนสุดของรหัสของคุณ: 1) #define __USE_POSIX199309และ #define _POSIX_C_SOURCE 199309L2) ทั้งสองจะต้องได้รับโค้ดเพื่อคอมไพล์โดยไม่มีคำเตือนใด ๆ (และเพื่อใช้nanoseconds()ฟังก์ชันที่มีให้)
Gabriel Staples

คำตอบที่เกี่ยวข้องฉันเพิ่งทำ: stackoverflow.com/a/55860234/4561887
Gabriel Staples

33

อีกทางเลือกหนึ่งusleep()ซึ่งไม่ได้กำหนดไว้ใน POSIX 2008 (แม้ว่าจะถูกกำหนดไว้จนถึง POSIX 2004 และเห็นได้ชัดว่ามีให้ใช้งานบน Linux และแพลตฟอร์มอื่น ๆ ที่มีประวัติการปฏิบัติตาม POSIX) มาตรฐาน POSIX 2008 กำหนดnanosleep():

nanosleep - การนอนหลับที่มีความละเอียดสูง

#include <time.h>
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);

nanosleep()ฟังก์ชั่นจะทำให้เกิดเธรดปัจจุบันจะถูกระงับจากการดำเนินการจนกว่าจะมีช่วงเวลาที่ระบุโดยrqtpอาร์กิวเมนต์ผ่านไปหรือสัญญาณจะถูกส่งไปด้ายโทรและการกระทำของมันคือการเรียกใช้งานฟังก์ชั่นสัญญาณจับหรือจะยุติกระบวนการ เวลาระงับอาจนานกว่าที่ร้องขอเนื่องจากค่าอาร์กิวเมนต์ถูกปัดเศษขึ้นเป็นจำนวนเต็มผลคูณของการแก้ปัญหาการนอนหลับหรือเนื่องจากระบบกำหนดเวลากิจกรรมอื่น ๆ แต่ยกเว้นในกรณีที่สัญญาณถูกขัดจังหวะเวลาการระงับจะต้องไม่น้อยกว่าเวลาที่ระบุโดยrqtpนาฬิการะบบ CLOCK_REALTIME วัดได้

การใช้nanosleep()ฟังก์ชั่นไม่มีผลต่อการกระทำหรือการอุดตันของสัญญาณใด ๆ


25

นอกเหนือจากการนอนหลับการเลือกที่ต่ำต้อยด้วยชุดตัวอธิบายไฟล์ NULL จะช่วยให้คุณหยุดชั่วคราวด้วยความแม่นยำระดับไมโครวินาทีและไม่ต้องเสี่ยงกับSIGALRMภาวะแทรกซ้อน

sigtimedwait และ sigwaitinfoมีพฤติกรรมที่คล้ายกัน


1
'โดยไม่ต้องเสี่ยงซิกาลาร์ม': ความเสี่ยงใดและกรณีใด? เรียกการนอนหลับและหลับใหล?
Massimo

2
@Massimo ข้อมูลจำเพาะที่เชื่อมโยงสำหรับusleepมีหลายประโยคเกี่ยวกับพฤติกรรม SIGALARM ที่ไม่ได้ระบุ (โดยทั่วไปusleepและนอนหลับได้รับอนุญาตให้ดำเนินการผ่านทางเก่าปลุกกลไกซึ่งคุณสามารถจินตนาการจะมีความซับซ้อนการใช้งานที่ปลอดภัยของusleepและ SIGALARM. ผมไม่ทราบว่าระบบที่ทันสมัยใด ๆ ที่ไม่ว่าวิธีนี้ แต่มันก็ยังคงอยู่ใน spec.)
pilcrow


-8
#include <stdio.h>
#include <stdlib.h>
int main () {

puts("Program Will Sleep For 2 Seconds");

system("sleep 2");      // works for linux systems


return 0;
}

1
สิ่งนี้จะไม่นอนเป็นเวลามิลลิวินาทีและยังแนะนำค่าใช้จ่ายเพิ่มเติมอีกมากซึ่งทำให้เวลาไม่น่าเชื่อถือมากขึ้น
Devolus

1
ตัวอย่างไม่สลีปเป็นไมโครวินาทีแถมนี่ไม่ใช่วิธีแก้ปัญหาที่ดีเมื่อเทียบกับการใช้สิ่งที่เหมือนกับ usleep ()
Victor Ocampo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.