<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>路上 &#187; scheduling</title>
	<atom:link href="http://www.speedvi.net/tag/scheduling/feed" rel="self" type="application/rss+xml" />
	<link>http://www.speedvi.net</link>
	<description>为者常成 行者常至</description>
	<lastBuildDate>Sat, 12 Jun 2010 06:30:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>实际系统中的调度</title>
		<link>http://www.speedvi.net/2010/02/26/214.html</link>
		<comments>http://www.speedvi.net/2010/02/26/214.html#comments</comments>
		<pubDate>Fri, 26 Feb 2010 07:20:10 +0000</pubDate>
		<dc:creator>行者</dc:creator>
				<category><![CDATA[操作系统]]></category>
		<category><![CDATA[scheduling]]></category>
		<category><![CDATA[多线程]]></category>
		<category><![CDATA[核心编程]]></category>
		<category><![CDATA[线程]]></category>
		<category><![CDATA[调度]]></category>

		<guid isPermaLink="false">http://www.speedvi.net/2010/02/26/214.html</guid>
		<description><![CDATA[　　我们已经谈过调度算法以及线程状态，但是我们还没有说过线程等重新调度的原因与时间。有一个常见的误解就是：重新调度的发生是没有什么原因的。这在设计阶段是一个有用的概念。但是更重要的是你要知道产生重新调度的条件。 　　重新调度只会由于以下几个原因才会发生： &#160; 硬件中断 内核调用 出错 硬件中断引起的重新调度 　　硬件中断引起的重新调度有两种情况：定时计数器产生的和其他硬件产生的。 　　实时时钟为内核生成周期性的中断，并引发基于时间的重新调度。 　　例如，如果你调用了函数sleep(10);，就会产生数个实时时钟中断；内核在每个中断为时间时钟做递增操作。当时间时钟表示已经过了10秒了，内核就会将你的线程重新调度为就绪状态。 　　其他线程可能等待从外设传来的硬件中断，比如串口、硬盘或声卡。在这种情况下，这些线程在内核中阻塞并等待硬件中断，只有“事件”发生后，这些线程才会被重新调度。 内核调用引起的重新调度 　　假设重新调度是由于一个线程做了内核调用所引起的，那么重新调度就会立即执行并可以看作与定时计数器和其他中断是异步的。 　　例如，上面我们调用了sleep函数，这个C库函数最终被转换为一个内核调用。在那时，内核就做出重新调度的决策并将你的线程从对应优先级的就绪队列取出，之后调度另外一个已经是就绪状态的线程。 　　有很多内核调用可以让一个进程重新调度。很多调用是非常明显的，如下面所示： 定时计数器函数（例如sleep()） 消息函数（例如MsgSendv()） 线程操作函数（例如pthread_cancel()、pthreaf_join()） 意外引起的重新调度 　　最后一个产生重新调度的原因，CPU错误，就是一个意外，它介于硬件中断与内核调用之间。它与内核（像中断）是异步执行的，可是与产生它的用户代码（像内核调用，比如除以0意外）是同步执行的。上面的两类重新调度也适用于由错误产生的重新调度。 总结 　　Neutrino提供了对于线程这个主要的调度元素的丰富的调度选项。进程则被定义为资源拥有权的一个单元并包含一个或多个线程。 　　线程可能会使用下面的任意一种同步方式： 互斥体(mutexes)：在一个时刻只允许一个线程拥有互斥体 信号量(semaphores)：允许规定数量的线程拥有信号量 睡眠锁(sleepons)：允许多个线程对一定数量的对象阻塞，在底层则是动态的为阻塞线程分配条件变量 条件变量(condvars)：与睡眠锁类似，不过条件变量的分配由编程者控制 连接(joining)：允许一个线程与其他线程同步结束 壁垒(barriers)：运行线程等待，直到一定数目的线程到达同步点 　　注意的是互斥体、信号量以及条件变量可以在同进程或不同进程的线程间使用，睡眠锁只能在同一进程中的线程之间使用。 　　除了同步之外，线程可以被重新调度（使用优先级以及调度算法），并且它们可以在单处理器系统或SMP系统上自动运行。 　　每次我们创建进程，实际上就是创建有一个进程在其中运行的地址空间，这个线程可能以来调用的函数由main()、fork()或vfork()启动。 Related posts:进程与线程 信号变量(Semaphores) 　　现在把场景从卫生间转移到厨房，同一时间在厨房里面有几个人是可以接受的。在厨房里面，你也可能不想让所有的人同时进入。实际上，你可能是想让厨房中的人数保持在你设定的限度之内。 　　比如你不想在任何时间点厨房中的人数超过两个。这可以使用互斥体来实现么？根据我们的定义，是不行的。为什么不行就是我们的比喻中的一个非常有趣的问题。 计数为1的信号变量 　　卫生间可能遇到的情况是以下两种情况之一，有两种状态是互相关联的： 门是开的并且无人在房间内 门被锁住并且有一个人在房间内 &#160; 　　至于其他的组合是不存在的——房间内没人门是不会被锁住的（如果这样的话，我们该如何打开这个门呢？），而有人在房间里面门也是不能被打开的（如果打开的话，如何保证他们的隐私？）。这就是计数为一的信号变量的例子——在那个房间里面最多只能有一个人，或是一个线程在使用这个信号变量。 　　这里的关键就是我们描绘这个锁的方式。对于常见的卫生间门锁，你可以在内部开关这个锁——不存在可以在外部开锁的钥匙。实际上，互斥体的拥有是一个元素级的操作——当你正在执行获取互斥体的操作的时候，别的线程是没有机会获取它的，而产生有两个线程同时拥有互斥体的情况。在我们的这个房子的比喻中，这不是那么明显，因为人类比1与0要聪明多了。... 进程间通信的共享内存 　　共享内存提供了进程间通信所能实现的最高带宽。一个共享内存对象创建之后，可以访问这个对象的进程就能够使用指针直接对其读写。这就意味着，共享内存访问本身就是非同步的。如果一个进程更新共享内存的一个区域，就必须特别小心不要让其他进程读取或更新同一块区域。即使是最简单的读取操作时，其他进程仍然有可能读到变化与不稳定的数据。 　　为了解决这个问题，共享内存就常与其他同步原(synchronization primitives)结合在一起使用以使进程之间的内存更新原子化。如果更新的间距很小，同步原就会限制自己固有的使用共享内存的高带宽。共享内存用于以块的模式更新大量的数据是最有效的。 　　信号量(semaphores)与互斥体(mutexes)都是适用与共享内存结合使用的同步原。信号量是在创建进程间同步的POSIX实时标准时引入的。互斥体则是在创建线程同步的POSIX标准是引入的。互斥体也可以在不同进程中的线程之间使用。POSIX将其作为一个可选的能力，我们在这里则是支持的。一般来说，互斥体要比信号量效率更高。 用于消息传递的共享内存 　　共享内存与消息传递可以结合起来以提供支持以下功能的IPC： 非常高的性能(共享内存) 同步(消息传递) 网络透明(消息传递) &#160;... [...]


Related posts:<ol><li><a href='http://www.speedvi.net/2009/12/23/182.html' rel='bookmark' title='进程与线程'>进程与线程</a> <small>信号变量(Semaphores) 　　现在把场景从卫生间转移到厨房，同一时间在厨房里面有几个人是可以接受的。在厨房里面，你也可能不想让所有的人同时进入。实际上，你可能是想让厨房中的人数保持在你设定的限度之内。 　　比如你不想在任何时间点厨房中的人数超过两个。这可以使用互斥体来实现么？根据我们的定义，是不行的。为什么不行就是我们的比喻中的一个非常有趣的问题。 计数为1的信号变量 　　卫生间可能遇到的情况是以下两种情况之一，有两种状态是互相关联的： 门是开的并且无人在房间内 门被锁住并且有一个人在房间内 &nbsp; 　　至于其他的组合是不存在的——房间内没人门是不会被锁住的（如果这样的话，我们该如何打开这个门呢？），而有人在房间里面门也是不能被打开的（如果打开的话，如何保证他们的隐私？）。这就是计数为一的信号变量的例子——在那个房间里面最多只能有一个人，或是一个线程在使用这个信号变量。 　　这里的关键就是我们描绘这个锁的方式。对于常见的卫生间门锁，你可以在内部开关这个锁——不存在可以在外部开锁的钥匙。实际上，互斥体的拥有是一个元素级的操作——当你正在执行获取互斥体的操作的时候，别的线程是没有机会获取它的，而产生有两个线程同时拥有互斥体的情况。在我们的这个房子的比喻中，这不是那么明显，因为人类比1与0要聪明多了。...</small></li>
<li><a href='http://www.speedvi.net/2009/09/28/177.html' rel='bookmark' title='进程间通信的共享内存'>进程间通信的共享内存</a> <small>　　共享内存提供了进程间通信所能实现的最高带宽。一个共享内存对象创建之后，可以访问这个对象的进程就能够使用指针直接对其读写。这就意味着，共享内存访问本身就是非同步的。如果一个进程更新共享内存的一个区域，就必须特别小心不要让其他进程读取或更新同一块区域。即使是最简单的读取操作时，其他进程仍然有可能读到变化与不稳定的数据。 　　为了解决这个问题，共享内存就常与其他同步原(synchronization primitives)结合在一起使用以使进程之间的内存更新原子化。如果更新的间距很小，同步原就会限制自己固有的使用共享内存的高带宽。共享内存用于以块的模式更新大量的数据是最有效的。 　　信号量(semaphores)与互斥体(mutexes)都是适用与共享内存结合使用的同步原。信号量是在创建进程间同步的POSIX实时标准时引入的。互斥体则是在创建线程同步的POSIX标准是引入的。互斥体也可以在不同进程中的线程之间使用。POSIX将其作为一个可选的能力，我们在这里则是支持的。一般来说，互斥体要比信号量效率更高。 用于消息传递的共享内存 　　共享内存与消息传递可以结合起来以提供支持以下功能的IPC： 非常高的性能(共享内存) 同步(消息传递) 网络透明(消息传递) &nbsp;...</small></li>
<li><a href='http://www.speedvi.net/2009/09/23/157.html' rel='bookmark' title='线程的调度'>线程的调度</a> <small>线程调度的决策时间 　　一旦由于内核调用、例外或者是硬件中断而开始系统微内核的调用，正在运行中的线程就会被暂停。只要任何线程的运行发生改变就要做出一个线程调度的决策，不管这个线程位于哪个进程中。所有进程中的线程是全局调度的。 　　一般来说暂停的线程会恢复运行，但是线程调度器当一个运行中的线程被阻塞、被其他线程抢先或者是自释放的时候就要完成从一个线程到另一个线程的环境转换。...</small></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>　　我们已经谈过调度算法以及线程状态，但是我们还没有说过线程等重新调度的原因与时间。有一个常见的误解就是：重新调度的发生是没有什么原因的。这在设计阶段是一个有用的概念。但是更重要的是你要知道产生重新调度的条件。</p>
<p>　　重新调度只会由于以下几个原因才会发生：</p>
<p><span id="more-214"></span>
<p>&nbsp;</p>
<ul>
<li>硬件中断</li>
<li>内核调用</li>
<li>出错</li>
</ul>
<h5>硬件中断引起的重新调度</h5>
<p>　　硬件中断引起的重新调度有两种情况：定时计数器产生的和其他硬件产生的。</p>
<p>　　实时时钟为内核生成周期性的中断，并引发基于时间的重新调度。</p>
<p>　　例如，如果你调用了函数sleep(10);，就会产生数个实时时钟中断；内核在每个中断为时间时钟做递增操作。当时间时钟表示已经过了10秒了，内核就会将你的线程重新调度为就绪状态。</p>
<p>　　其他线程可能等待从外设传来的硬件中断，比如串口、硬盘或声卡。在这种情况下，这些线程在内核中阻塞并等待硬件中断，只有“事件”发生后，这些线程才会被重新调度。</p>
<h5>内核调用引起的重新调度</h5>
<p>　　假设重新调度是由于一个线程做了内核调用所引起的，那么重新调度就会立即执行并可以看作与定时计数器和其他中断是异步的。</p>
<p>　　例如，上面我们调用了sleep函数，这个C库函数最终被转换为一个内核调用。在那时，内核就做出重新调度的决策并将你的线程从对应优先级的就绪队列取出，之后调度另外一个已经是就绪状态的线程。</p>
<p>　　有很多内核调用可以让一个进程重新调度。很多调用是非常明显的，如下面所示：</p>
<ul>
<li>定时计数器函数（例如sleep()）</li>
<li>消息函数（例如MsgSendv()）</li>
<li>线程操作函数（例如pthread_cancel()、pthreaf_join()）</li>
</ul>
<h5>意外引起的重新调度</h5>
<p>　　最后一个产生重新调度的原因，CPU错误，就是一个意外，它介于硬件中断与内核调用之间。它与内核（像中断）是异步执行的，可是与产生它的用户代码（像内核调用，比如除以0意外）是同步执行的。上面的两类重新调度也适用于由错误产生的重新调度。</p>
<h5>总结</h5>
<p>　　Neutrino提供了对于线程这个主要的调度元素的丰富的调度选项。进程则被定义为资源拥有权的一个单元并包含一个或多个线程。</p>
<p>　　线程可能会使用下面的任意一种同步方式：</p>
<ul>
<li>互斥体(mutexes)：在一个时刻只允许一个线程拥有互斥体</li>
<li>信号量(semaphores)：允许规定数量的线程拥有信号量</li>
<li>睡眠锁(sleepons)：允许多个线程对一定数量的对象阻塞，在底层则是动态的为阻塞线程分配条件变量</li>
<li>条件变量(condvars)：与睡眠锁类似，不过条件变量的分配由编程者控制</li>
<li>连接(joining)：允许一个线程与其他线程同步结束</li>
<li>壁垒(barriers)：运行线程等待，直到一定数目的线程到达同步点</li>
</ul>
<p>　　注意的是互斥体、信号量以及条件变量可以在同进程或不同进程的线程间使用，睡眠锁只能在同一进程中的线程之间使用。</p>
<p>　　除了同步之外，线程可以被重新调度（使用优先级以及调度算法），并且它们可以在单处理器系统或SMP系统上自动运行。</p>
<p>　　每次我们创建进程，实际上就是创建有一个进程在其中运行的地址空间，这个线程可能以来调用的函数由main()、fork()或vfork()启动。</p>


<p>Related posts:<ol><li><a href='http://www.speedvi.net/2009/12/23/182.html' rel='bookmark' title='进程与线程'>进程与线程</a> <small>信号变量(Semaphores) 　　现在把场景从卫生间转移到厨房，同一时间在厨房里面有几个人是可以接受的。在厨房里面，你也可能不想让所有的人同时进入。实际上，你可能是想让厨房中的人数保持在你设定的限度之内。 　　比如你不想在任何时间点厨房中的人数超过两个。这可以使用互斥体来实现么？根据我们的定义，是不行的。为什么不行就是我们的比喻中的一个非常有趣的问题。 计数为1的信号变量 　　卫生间可能遇到的情况是以下两种情况之一，有两种状态是互相关联的： 门是开的并且无人在房间内 门被锁住并且有一个人在房间内 &nbsp; 　　至于其他的组合是不存在的——房间内没人门是不会被锁住的（如果这样的话，我们该如何打开这个门呢？），而有人在房间里面门也是不能被打开的（如果打开的话，如何保证他们的隐私？）。这就是计数为一的信号变量的例子——在那个房间里面最多只能有一个人，或是一个线程在使用这个信号变量。 　　这里的关键就是我们描绘这个锁的方式。对于常见的卫生间门锁，你可以在内部开关这个锁——不存在可以在外部开锁的钥匙。实际上，互斥体的拥有是一个元素级的操作——当你正在执行获取互斥体的操作的时候，别的线程是没有机会获取它的，而产生有两个线程同时拥有互斥体的情况。在我们的这个房子的比喻中，这不是那么明显，因为人类比1与0要聪明多了。...</small></li>
<li><a href='http://www.speedvi.net/2009/09/28/177.html' rel='bookmark' title='进程间通信的共享内存'>进程间通信的共享内存</a> <small>　　共享内存提供了进程间通信所能实现的最高带宽。一个共享内存对象创建之后，可以访问这个对象的进程就能够使用指针直接对其读写。这就意味着，共享内存访问本身就是非同步的。如果一个进程更新共享内存的一个区域，就必须特别小心不要让其他进程读取或更新同一块区域。即使是最简单的读取操作时，其他进程仍然有可能读到变化与不稳定的数据。 　　为了解决这个问题，共享内存就常与其他同步原(synchronization primitives)结合在一起使用以使进程之间的内存更新原子化。如果更新的间距很小，同步原就会限制自己固有的使用共享内存的高带宽。共享内存用于以块的模式更新大量的数据是最有效的。 　　信号量(semaphores)与互斥体(mutexes)都是适用与共享内存结合使用的同步原。信号量是在创建进程间同步的POSIX实时标准时引入的。互斥体则是在创建线程同步的POSIX标准是引入的。互斥体也可以在不同进程中的线程之间使用。POSIX将其作为一个可选的能力，我们在这里则是支持的。一般来说，互斥体要比信号量效率更高。 用于消息传递的共享内存 　　共享内存与消息传递可以结合起来以提供支持以下功能的IPC： 非常高的性能(共享内存) 同步(消息传递) 网络透明(消息传递) &nbsp;...</small></li>
<li><a href='http://www.speedvi.net/2009/09/23/157.html' rel='bookmark' title='线程的调度'>线程的调度</a> <small>线程调度的决策时间 　　一旦由于内核调用、例外或者是硬件中断而开始系统微内核的调用，正在运行中的线程就会被暂停。只要任何线程的运行发生改变就要做出一个线程调度的决策，不管这个线程位于哪个进程中。所有进程中的线程是全局调度的。 　　一般来说暂停的线程会恢复运行，但是线程调度器当一个运行中的线程被阻塞、被其他线程抢先或者是自释放的时候就要完成从一个线程到另一个线程的环境转换。...</small></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.speedvi.net/2010/02/26/214.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

