fbpx
维基百科

忙碌等待

软件工程中,忙碌等待(也称自旋;英語:Busy waiting、busy-looping、spinning)是一种以进程反复检查一个条件是否为真为根本的技术,条件可能为键盘输入或某个锁是否可用。忙碌等待也可以用来产生一个任意的时间延迟,若系统没有提供生成特定时间长度的方法,则需要用到忙碌等待。不同的计算机处理器速度差异很大,特别是一些处理器设计为可能根据外部因素(例如操作系统上的负载)动态调整速率。因此,忙碌等待这种时间延迟技术容易产生不可预知、甚至不一致的结果,除非实现代码来确定处理器执行“什么都不做”循环的速度,或者循环代码明确检查实时时钟

在某些情况下,忙碌等待是有效的策略,特别是实现自旋锁设计的操作系统上运行對稱多處理。不過一般来说,忙碌等待是应该避免的反模式[1],处理器时间應該用来执行其他任务,而不是浪费在无用的活动上。

对于多核CPU,忙碌等待的优点是不切换线程,避免了由此付出的代价。因此一些多线程同步机制不使用切换到内核态的同步对象,而是以用户态的自旋锁或其衍生机制(如轻型读写锁)来做同步,付出的时间复杂度相差3个数量级。忙碌等待可使用一些机制来降低CPU功耗,如Windows系统中调用YieldProcessor,实际上是调用了SIMD指令_mm_pause。[來源請求]

C語言的範例程式 编辑

以下的C語言程式示範二個線程共享一個全域變數i,第一個線程用忙碌等待來確認變數i的值是否有改變。

#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <stdlib.h>  volatile int i = 0; /* i is global, so it is visible to all functions.  It's also marked volatile, because it  may change in a way which is not predictable by the compiler,  here from a different thread. */  /* f1 uses a spinlock to wait for i to change from 0. */ static void *f1(void *p) {  while (i == 0) {  /* do nothing - just keep checking over and over */  }  printf("i's value has changed to %d.\n", i);  return NULL; }  static void *f2(void *p) {  sleep(60); /* sleep for 60 seconds */  i = 99;  printf("t2 has changed the value of i to %d.\n", i);  return NULL; }  int main() {  int rc;  pthread_t t1, t2;  rc = pthread_create(&t1, NULL, f1, NULL);  if (rc != 0) {  fprintf(stderr, "pthread f1 failed\n");  return EXIT_FAILURE;  }  rc = pthread_create(&t2, NULL, f2, NULL);  if (rc != 0) {  fprintf(stderr, "pthread f2 failed\n");  return EXIT_FAILURE;  }  pthread_join(t1, NULL);  pthread_join(t2, NULL);  puts("All pthreads finished.");  return 0; } 

上述的程式也可以用C11標準中的條件變數達成。

忙碌等待的替代品 编辑

大多数操作系统和线程库提供了各种各樣可以阻止事件过程的系统调用,如锁获取、计时器变化,I/O可用性或信號。使用系统调用來產生延遲會有最简单、最有效、公平且沒有競爭危害的結果。一个调用會检查、通知事件等待的调度程序,插入一个适用的记忆障碍,也可以在返回之前执行所请求的I / O操作。當调用者被堵住時,其他进程可以使用CPU。调度器有实现优先级继承所需的信息或其他机制,来避免资源衰竭英语Resource starvation的問題。

在大部份操作系统中,也可以在忙碌等待中加入延迟函数(sleep()),以減少忙碌等待浪费的CPU資源。这可以讓线程暫停指定的时间,在此期间线程不会浪费CPU时间。如果循环检查只是檢查一些简单的事務,将大部分时间花费在延迟函数,则不太會浪费太多CPU时间。

若程序永远不会结束(如操作系统),可以通过无条件跳转(例如NASM語法中的jmp $)实现无限次的忙碌等待。CPU会永远无条件跳转到程式現在執行到的位置。因此可以用以下的程式取代忙碌等待:

sleep: hlt jmp sleep 

适当的使用忙碌等待 编辑

一些底层编程中可能需要用到需忙碌等待。對每個硬體設備(尤其是偶爾才使用到的硬體)設置中斷可能不切实际甚至不可能。有时需要將某种的控制数据写入硬件,在写入後获取设备状态,但状态可能要在寫入後數個機器週期後才有效。程序员可以调用操作系统延迟函数,不過这样做可能要耗費更多的时钟周,此時就可以使用忙碌等待。

相關條目 编辑

參考資料 编辑

  1. ^ Why the "volatile" type class should not be used 互联网档案馆的,存档日期2013-11-02.

忙碌等待, 此條目需要补充更多来源, 2014年12月1日, 请协助補充多方面可靠来源以改善这篇条目, 无法查证的内容可能會因為异议提出而被移除, 致使用者, 请搜索一下条目的标题, 来源搜索, 网页, 新闻, 书籍, 学术, 图像, 以检查网络上是否存在该主题的更多可靠来源, 判定指引, 此條目需要精通或熟悉相关主题的编者参与及协助编辑, 2014年11月28日, 請邀請適合的人士改善本条目, 更多的細節與詳情請參见討論頁, 在软件工程中, 也称自旋, 英語, busy, waiting, busy, loopi. 此條目需要补充更多来源 2014年12月1日 请协助補充多方面可靠来源以改善这篇条目 无法查证的内容可能會因為异议提出而被移除 致使用者 请搜索一下条目的标题 来源搜索 忙碌等待 网页 新闻 书籍 学术 图像 以检查网络上是否存在该主题的更多可靠来源 判定指引 此條目需要精通或熟悉相关主题的编者参与及协助编辑 2014年11月28日 請邀請適合的人士改善本条目 更多的細節與詳情請參见討論頁 在软件工程中 忙碌等待 也称自旋 英語 Busy waiting busy looping spinning 是一种以进程反复检查一个条件是否为真为根本的技术 条件可能为键盘输入或某个锁是否可用 忙碌等待也可以用来产生一个任意的时间延迟 若系统没有提供生成特定时间长度的方法 则需要用到忙碌等待 不同的计算机处理器速度差异很大 特别是一些处理器设计为可能根据外部因素 例如操作系统上的负载 动态调整速率 因此 忙碌等待这种时间延迟技术容易产生不可预知 甚至不一致的结果 除非实现代码来确定处理器执行 什么都不做 循环的速度 或者循环代码明确检查实时时钟 在某些情况下 忙碌等待是有效的策略 特别是实现自旋锁设计的操作系统上运行對稱多處理 不過一般来说 忙碌等待是应该避免的反模式 1 处理器时间應該用来执行其他任务 而不是浪费在无用的活动上 对于多核CPU 忙碌等待的优点是不切换线程 避免了由此付出的代价 因此一些多线程同步机制不使用切换到内核态的同步对象 而是以用户态的自旋锁或其衍生机制 如轻型读写锁 来做同步 付出的时间复杂度相差3个数量级 忙碌等待可使用一些机制来降低CPU功耗 如Windows系统中调用YieldProcessor 实际上是调用了SIMD指令 mm pause 來源請求 目录 1 C語言的範例程式 2 忙碌等待的替代品 3 适当的使用忙碌等待 4 相關條目 5 參考資料C語言的範例程式 编辑以下的C語言程式示範二個線程共享一個全域變數i 第一個線程用忙碌等待來確認變數i的值是否有改變 include lt stdio h gt include lt pthread h gt include lt unistd h gt include lt stdlib h gt volatile int i 0 i is global so it is visible to all functions It s also marked volatile because it may change in a way which is not predictable by the compiler here from a different thread f1 uses a spinlock to wait for i to change from 0 static void f1 void p while i 0 do nothing just keep checking over and over printf i s value has changed to d n i return NULL static void f2 void p sleep 60 sleep for 60 seconds i 99 printf t2 has changed the value of i to d n i return NULL int main int rc pthread t t1 t2 rc pthread create amp t1 NULL f1 NULL if rc 0 fprintf stderr pthread f1 failed n return EXIT FAILURE rc pthread create amp t2 NULL f2 NULL if rc 0 fprintf stderr pthread f2 failed n return EXIT FAILURE pthread join t1 NULL pthread join t2 NULL puts All pthreads finished return 0 上述的程式也可以用C11標準中的條件變數達成 忙碌等待的替代品 编辑大多数操作系统和线程库提供了各种各樣可以阻止事件过程的系统调用 如锁获取 计时器变化 I O可用性或信號 使用系统调用來產生延遲會有最简单 最有效 公平且沒有競爭危害的結果 一个调用會检查 通知事件等待的调度程序 插入一个适用的记忆障碍 也可以在返回之前执行所请求的I O操作 當调用者被堵住時 其他进程可以使用CPU 调度器有实现优先级继承所需的信息或其他机制 来避免资源衰竭 英语 Resource starvation 的問題 在大部份操作系统中 也可以在忙碌等待中加入延迟函数 sleep 以減少忙碌等待浪费的CPU資源 这可以讓线程暫停指定的时间 在此期间线程不会浪费CPU时间 如果循环检查只是檢查一些简单的事務 将大部分时间花费在延迟函数 则不太會浪费太多CPU时间 若程序永远不会结束 如操作系统 可以通过无条件跳转 例如NASM語法中的jmp 实现无限次的忙碌等待 CPU会永远无条件跳转到程式現在執行到的位置 因此可以用以下的程式取代忙碌等待 sleep hlt jmp sleep适当的使用忙碌等待 编辑一些底层编程中可能需要用到需忙碌等待 對每個硬體設備 尤其是偶爾才使用到的硬體 設置中斷可能不切实际甚至不可能 有时需要將某种的控制数据写入硬件 在写入後获取设备状态 但状态可能要在寫入後數個機器週期後才有效 程序员可以调用操作系统延迟函数 不過这样做可能要耗費更多的时钟周 此時就可以使用忙碌等待 相關條目 编辑BogoMips Volatile變數 輪詢 自旋锁 同步 计算机科学 參考資料 编辑 Why the volatile type class should not be used 互联网档案馆的存檔 存档日期2013 11 02 取自 https zh wikipedia org w index php title 忙碌等待 amp oldid 60465659, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。