【问题标题】:c++ - how to know when the thread context switch happens?c++ - 如何知道线程上下文切换何时发生?
【发布时间】:2016-09-10 23:54:02
【问题描述】:

正如标题所说,在 c++ 中使用 std::threads 时,我们如何知道上下文切换何时发生

例如

void a()
{
   //some code
}                                    
void b(); 
{
   //some code 
}                                    

int main ()
{
  thread th1 (a);       
  thread th2 (b); 

  th1.join();                                        
  th2.join();                                       

  return 0;
} 

有没有办法知道操作系统何时进行线程切换,我们实际上可以在相应的函数正在处理时描绘像打印 a 或 b。

注意:我使用了互斥锁和控制变量,在它们上面放置了一个简单的 cout

【问题讨论】:

  • 你没有。这是操作系统的工作,知道何时切换线程上下文。而在现代的多 CPU 硬件上,甚至可能没有线程上下文切换,每个线程都分配了一个单独的 CPU,并且一切都同时运行。你想解决什么问题?不,不是关于知道何时存在线程上下文切换的问题,而是您认为解决方案是知道何时存在线程上下文切换。
  • @SamVarshavchik 我刚做了一个有两个线程的程序,想打印当前正在处理的进程
  • 线程的关键在于它们是独立的指令流,因此线程不可能检测它们之间的上下文切换。显然,操作系统调度程序将管理/跟踪此类信息,但不会使切换对受影响的线程显而易见。如果您试图检测这样的事情,您可能需要对共享数据的访问进行某种同步(例如临界区、互斥体、使用原子变量),或者等待线程完成(例如加入)。
  • 我确信有一个特定于操作系统的资源可以用来查看当前正在运行的线程。问题是,当您获得并设法打印它时,可能正在运行不同的线程。这完全没有任何作用。

标签: c++ multithreading


【解决方案1】:

可能没有需要了解的上下文切换。

在具有两个(或更多)内核的机器上,您的两个线程可能同时运行,在完成之前根本不会发生上下文切换。

请记住,大多数当前机器至少有两个内核,而具有 4 到 8 个内核的机器已经相当普遍。假设这样的代码会导致 any 上下文切换基本上是过时的。从理论上讲,它已经过时了很长时间(即,并行机器已经几十年了)。

现在它实际上已经完全过时了——即使你通过翻找别人赠送或捐赠的垃圾来获得你的新计算机,他们的旧垃圾至少有两个内核和四个内核的可能性仍然很大。完全没有问题。

【讨论】:

  • 另外请记住,@JerryCoffin,无论 CPU 有多少内核,负载足够大的操作系统都会切换线程。换句话说,如果这个问题停留在教学/演示区域,您可以安排条件显示线程上下文切换。
  • @AdrianColomitchi:哦,毫无疑问,上下文切换可以、确实并且仍然会发生——但根据负载,它们很容易变得非常罕见,以至于您可能不得不(例如)运行在你看到一个发生之前多次编程(即使假设你编写代码来正确检测一个)。
  • “您可能必须(例如)多次运行程序才能看到一个发生”:D 或者打开足够多的 Firefox 标签,全部运行“nyan cat”:D
  • @AdrianColomitchi:我怀疑您设置的音量对 CPU 使用率有很大(任何?)影响(除了说服我更快地关闭它,从而消除影响)。 :-)
  • :) 好吧,说到特意安排的设置,用消耗更高电流的扬声器替换扬声器可能会因 PSU 过载而使 CPU 饿死。但我们需要将讨论转移到 EE 网站上以探索后果:)
【解决方案2】:

我们实际上可以描绘在相应的函数正在处理时打印 a 或 b。

如果这仅用于演示/教学目的

让我用这个比喻:你有一个黑盒控制器(操作系统),它通过两个二极管(线程)推动电流。由于您对控制器没有任何命令,因此查看电流流过哪条路径的唯一方法是用 LED-es 替换二极管 - 在电流流过它们的所有时刻,它们都会发光。 (注意:由于 LED 可能不等同于它所取代的二极管,因此您不会想出售可能会吹出神奇烟雾的产品 - 也就是说“不要在实验室内的诊断案例之外使用这种技术")

就您的a()b() 函数而言,这转化为使它们在它们执行的每条指令中“发光”(或者这些指令足以实现演示目的)。

因此,编写一个包装这些指令的宏,除了执行指令之外,它们还有一个副作用,您可以使用它来检测哪些线程正在运行。 请注意:它们可以同时在两个不同的 CPU 内核上运行。


该技术通常被称为“仪器”,它被例如性能评估工具使用(针对特定情况进行调整)。

【讨论】:

  • 你的回答很好,我去看看。如果你知道的话,你能提供一个简单的仪器例子吗?
  • @AlberttheKing 如果您要求使用此技术的工具,请查看gprof 和相关示例(需要使用-pg 标志编译程序,生成的代码将拦截开始/结束函数的执行 - gprof 允许您探索执行产生的时序数据)。如果您询问如何在您的案例中使用此技术的示例,我可能会尝试在确认这是您想要的之后绘制一些东西。
【解决方案3】:

你无法知道,也没有理由知道。

内核/硬件线程和上下文管理背后的驱动原则之一就是使整个过程对您不可见。如果两个线程(系统上的其他线程除外)运行在不同的内核上,甚至可能没有任何上下文切换。

如果您认为需要这样做,您可能需要坐下来重新考虑您的设计,并熟悉通常可供您使用的各种同步结构。

【讨论】:

  • 如果您调试代码,您实际上可以看到接下来正在处理哪个线程,所以我希望用户看到该开关
  • @AlberttheKing 我认为您混淆了几件事。没有调试器会告诉您下一个正在处理哪个线程。他们可以告诉你的是你创建的所有线程的列表,以及当你暂停它时恰好正在运行的一些线程,以及调试器需要零知道上下文切换何时发生(如果发生)来向您提供此信息。您可以向用户提供的最好的信息是线程的 ID(不知道为什么要通过上下文切换通知来猛烈抨击用户,这可能每秒发生数百次)。
  • 是的,我可能将调试视为实际的线程切换
猜你喜欢
  • 1970-01-01
  • 2011-07-23
  • 2019-05-14
  • 1970-01-01
  • 1970-01-01
  • 2019-10-02
  • 2015-06-28
  • 2010-09-23
相关资源
最近更新 更多