Thread.Yield是否会让CPU上下文切换到同一进程或同一处理器中的其他线程?

时间:2014-02-07 07:38:31

标签: c# multithreading

我在Joseph Albahari的线程书(http://www.albahari.com/threading/

中看到以下内容
  

Thread.Sleep(0)放弃线程的当前时间片   立即,自愿将CPU交给其他线程。   Framework 4.0的新Thread.Yield()方法做了同样的事情 - 除了   它只放弃在同一处理器上运行的线程。

上下文切换是发生在同一进程中的某个其他线程还是等待获取CPU的线程中?

如果答案是后者,有没有办法在同一进程中上下文切换到处于等待状态的其他线程?

据我所知,操作系统已经完成了线程调度。但是,由于Thread.Sleep(0)并试图为它找到解决方案而遇到问题。

编辑以更清楚地了解问题:

软件有两个线程(比如A和B),A将等待来自B的信号20毫秒,无论信号如何都会继续。 A设置信号并让处理器继续使用B,Thread.Sleep(0)应用,因为软件是时间关键应用程序,每隔一秒。一秒钟A和B都没有继续和恢复(在日志的帮助下)。我们认为同一处理器中的其他一些进程获得了CPU时间片,现在正在寻找替代方案。

4 个答案:

答案 0 :(得分:2)

Thread.Yield方法将切换到准备在当前处理器上运行的任何线程。它没有区分

中存在Thread的过程

答案 1 :(得分:2)

即使是P / Invoke,也无法在同一进程中屈服于另一个线程。 Windows根本不支持它。

另一种方法是使用某种协作式多任务处理,例如TPL和async / await。当您await某些内容(例如Task.Yield()返回的等待对象)时,它会启用排队等待调度程序的另一个任务。它比使用Thread.Yield()效率更高,但是如果你还没有使用它,那么这可能需要对你的应用进行大规模的改造。

答案 2 :(得分:0)

Thread.Yield()只允许调度程序在准备运行的同一进程中选择另一个线程,并在停止的任何时刻恢复它。它与进程之间的时间切片无关,这是完全不同的事情。 (除非你正在编写其他过程,否则很少会引起关注。)

请注意,如果当前线程是唯一能够运行的线程,则Yield()可能完全没有效果。它只会从Yield()调用返回(相对立即)。

关于“在同一过程中上下文切换到另一个线程”的问题有点误导。你不应该用这些术语来思考。如果您需要等待另一个线程完成,请使用Join。如果你需要向另一个线程发出信号,它应该停止等待并做某事,那么有很多机制可供使用。

简而言之,如果你试图“推测”线程调度程序,你的问题会变得更糟。

也许您应该更明确地了解您实际遇到的问题。

答案 3 :(得分:0)

Thread是围绕OS线程的包装器。由于这个线程的调度由OS内核执行而且Yield只是告诉内核的一种方式,你想要放弃CPU但仍然保持可运行(未阻塞)。内核会将您的请求视为执行重新安排并将CPU提供给其他等待线程的好点。操作系统可以自由地将CPU提供给来自runqueue的任何等待线程,而忽略它所属的进程。除非它是您自己的调度程序并且您使用所谓的绿色线程和协作式多任务处理,否则无法影响调度程序决策。

关于您的问题:如果您想获得有保证的结果,则需要使用显式同步。 屈服是一种错误的方式,因为它不向你提供任何保证。 从使用中可以看出一系列问题。 例如,您的线程B可能根本没有足够的时间来完成其工作并在A将再次调度之前向A发送信号,A可以在Yield之后立即调度到另一个CPU核心,A甚至可以在B之前重新调度将有机会被处决。最后,其他应用程序可以占用CPU。如果你真的关心时间,那么提高两个线程的优先级,但明确地同步它们。