ให้ฉันอธิบายว่าทำไมsleep infinity
ทำงานแม้ว่ามันจะไม่ได้รับการบันทึกไว้ คำตอบของ jp48ก็มีประโยชน์เช่นกัน
สิ่งที่สำคัญที่สุด: โดยการระบุinf
หรือinfinity
(ทั้งตัวพิมพ์เล็กและใหญ่) คุณสามารถเข้าสู่โหมดสลีปเป็นเวลานานที่สุดที่ใบอนุญาตใช้งานของคุณ (เช่นค่าที่น้อยกว่าHUGE_VAL
และTYPE_MAXIMUM(time_t)
)
ทีนี้มาดูรายละเอียดกันดีกว่า รหัสที่มาของsleep
คำสั่งที่สามารถอ่านได้จากcoreutils / src / sleep.c ฟังก์ชั่นทำสิ่งนี้:
double s; //seconds
xstrtod (argv[i], &p, &s, cl_strtod); //`p` is not essential (just used for error check).
xnanosleep (s);
ความเข้าใจ xstrtod (argv[i], &p, &s, cl_strtod)
xstrtod()
ตามgnulib / lib / xstrtod.cโทรของxstrtod()
สตริงแปลงargv[i]
เป็นค่าจุดลอยและเก็บไว้เพื่อใช้ฟังก์ชั่นแปลง*s
cl_strtod()
cl_strtod()
ที่สามารถมองเห็นได้จากcoreutils / lib / CL-strtod.c , แปลงสตริงเป็นค่าจุดลอยโดยใช้cl_strtod()
strtod()
strtod()
ตามman 3 strtod
, แปลงสตริงค่าเป็นประเภทstrtod()
double
manpage พูดว่า
รูปแบบที่คาดหวังของสตริง (ส่วนเริ่มต้นของ) คือ ... หรือ (iii) อินฟินิตี้หรือ ...
และอินฟินิตี้หมายถึง
อนันต์คือ "INF" หรือ "INFINITY" โดยไม่สนใจขนาดตัวพิมพ์
แม้ว่าเอกสารจะบอก
หากค่าที่ถูกต้องจะทำให้เกิดการล้น, บวกหรือลบHUGE_VAL
( HUGE_VALF
, HUGE_VALL
) จะถูกส่งกลับ
มันไม่ชัดเจนว่าวิธีการปฏิบัติไม่มีที่สิ้นสุด ดังนั้นเรามาดูรหัสที่มาgnulib / lib / strtod.c สิ่งที่เราต้องการอ่านคือ
else if (c_tolower (*s) == 'i'
&& c_tolower (s[1]) == 'n'
&& c_tolower (s[2]) == 'f')
{
s += 3;
if (c_tolower (*s) == 'i'
&& c_tolower (s[1]) == 'n'
&& c_tolower (s[2]) == 'i'
&& c_tolower (s[3]) == 't'
&& c_tolower (s[4]) == 'y')
s += 5;
num = HUGE_VAL;
errno = saved_errno;
}
ดังนั้นINF
และINFINITY
(ทั้งกรณีตาย) HUGE_VAL
ได้รับการยกย่องว่าเป็น
HUGE_VAL
ครอบครัว
ลองใช้N1570เป็นมาตรฐาน C HUGE_VAL
, HUGE_VALF
และHUGE_VALL
แมโครที่กำหนดไว้ใน§7.12-3
มาโคร
HUGE_VAL
ขยายเป็นนิพจน์ค่าคงที่เป็นบวกสองเท่าซึ่งไม่จำเป็นต้องแทนค่าได้ในลักษณะลอยตัว แมโคร
HUGE_VALF
HUGE_VALL
จะลอยตามลำดับและ analogs HUGE_VAL
คู่ที่ยาวนานของ
HUGE_VAL
, HUGE_VALF
และHUGE_VALL
สามารถเป็นอนันต์เชิงบวกในการดำเนินการที่สนับสนุนอินฟินิตี้
และใน§7.12.1-5
หากผลลอยล้นและการปัดเศษเริ่มต้นมีผลแล้วฟังก์ชั่นส่งกลับค่าของแมโครHUGE_VAL
, HUGE_VALF
หรือHUGE_VALL
ตามประเภทผลตอบแทน
ความเข้าใจ xnanosleep (s)
xstrtod()
ตอนนี้เราเข้าใจสาระสำคัญทั้งหมดของ จากคำอธิบายข้างต้นก็คือคริสตัลที่ชัดเจนว่าเราได้เห็นเป็นครั้งแรกจริงหมายถึงxnanosleep(s)
xnanosleep(HUGE_VALL)
xnanosleep()
ตามซอร์สโค้ดgnulib / lib / xnanosleep.cส่วนxnanosleep(s)
ใหญ่ทำสิ่งนี้:
struct timespec ts_sleep = dtotimespec (s);
nanosleep (&ts_sleep, NULL);
dtotimespec()
ฟังก์ชั่นนี้จะแปลงข้อโต้แย้งของพิมพ์กับวัตถุของการพิมพ์double
struct timespec
เพราะมันเป็นเรื่องง่ายมากให้ฉันอ้างอิงรหัสที่มาgnulib / lib / dtotimespec.c ความคิดเห็นทั้งหมดถูกเพิ่มโดยฉัน
struct timespec
dtotimespec (double sec)
{
if (! (TYPE_MINIMUM (time_t) < sec)) //underflow case
return make_timespec (TYPE_MINIMUM (time_t), 0);
else if (! (sec < 1.0 + TYPE_MAXIMUM (time_t))) //overflow case
return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1);
else //normal case (looks complex but does nothing technical)
{
time_t s = sec;
double frac = TIMESPEC_HZ * (sec - s);
long ns = frac;
ns += ns < frac;
s += ns / TIMESPEC_HZ;
ns %= TIMESPEC_HZ;
if (ns < 0)
{
s--;
ns += TIMESPEC_HZ;
}
return make_timespec (s, ns);
}
}
เนื่องจากtime_t
ถูกกำหนดให้เป็นประเภทอินทิกรัล (ดู§7.27.1-3) มันเป็นธรรมชาติที่เราถือว่าค่าสูงสุดของประเภทtime_t
มีขนาดเล็กกว่าHUGE_VAL
(ของประเภทdouble
) ซึ่งหมายความว่าเราเข้าสู่กรณีโอเวอร์โฟลว์ (อันที่จริงข้อสมมติฐานนี้ไม่จำเป็นเนื่องจากในทุกกรณีขั้นตอนนั้นเหมือนกัน)
make_timespec()
make_timespec()
ผนังสุดท้ายที่เราต้องปีนขึ้นเป็น โชคดีมากมันง่ายมากที่จะอ้างถึงซอร์สโค้ดgnulib / lib / timespec.hก็เพียงพอแล้ว
_GL_TIMESPEC_INLINE struct timespec
make_timespec (time_t s, long int ns)
{
struct timespec r;
r.tv_sec = s;
r.tv_nsec = ns;
return r;
}