Questions tagged «multithreading»

与多线程相关的问题,包括技术,结构和安全性问题。

7
我是否应该不再使用不赞成使用的多线程和多处理器编程实践?
在FORTRAN和BASIC的早期,基本上所有程序都是使用GOTO语句编写的。结果是意大利面条代码,解决方案是结构化编程。 同样,指针可能很难控制我们程序中的特征。C ++从大量的指针开始,但是建议使用引用。像STL这样的库可以减少我们的依赖。还有一些习惯用法来创建具有更好特性的智能指针,并且某些版本的C ++允许引用和托管代码。 诸如继承和多态性之类的编程实践在幕后使用了许多指针(就像结构化编程生成充满分支指令的代码一样)。像Java这样的语言消除了指针,并使用垃圾回收来管理动态分配的数据,而不是依赖程序员来匹配其所有new和delete语句。 在我的阅读中,我看到了似乎不使用信号量的多进程和多线程编程的示例。他们是使用同一名称使用不同的名称还是使用新的方法来保护资源并发使用? 例如,使用多核处理器进行多线程编程的系统的特定示例是OpenMP。它代表以下一个关键区域,不使用信号量,该信号量似乎不包含在环境中。 th_id = omp_get_thread_num(); #pragma omp critical { cout << "Hello World from thread " << th_id << '\n'; } 本示例摘自:http : //en.wikipedia.org/wiki/OpenMP 或者,使用带有功能wait()和signal()的信号量对线程进行类似的保护,如下所示: wait(sem); th_id = get_thread_num(); cout << "Hello World from thread " << th_id << '\n'; signal(sem); 在此示例中,事情非常简单,只需简单的回顾就足以显示wait()和signal()调用是匹配的,即使有很多并发,也可以提供线程安全性。但是其他算法更复杂,并且使用多个信号量(二进制和计数),这些信号量分布在具有复杂条件的多个函数中,可以被许多线程调用。创建死锁或无法使线程安全的后果很难管理。 这些系统(例如OpenMP)是否消除了信号量的问题? 他们是否将问题转移到其他地方? 如何使用算法将自己喜欢的信号量转换为不再使用信号量?


3
为什么不绿线?
虽然我知道有关此问题的问题已经解决(例如https://stackoverflow.com/questions/5713142/green-threads-vs-non-green-threads),但我感觉自己并没有一个令人满意的答案。 问题是:为什么JVM不再支持绿色线程? 它在代码样式的Java FAQ上说了这一点: 绿色线程是指Java虚拟机(JVM)的一种操作模式,其中所有代码都在单个操作系统线程中执行。 然后在java.sun.com上: 不利之处在于,使用绿色线程意味着Linux上的系统线程无法得到利用,因此当添加其他CPU时Java虚拟机无法扩展。 在我看来,JVM可以具有等于内核数量的系统进程池,然后在此之上运行绿色线程。当您有大量经常阻塞的线程时(这可能是由于当前JVM限制了线程数),这可能会带来一些很大的优势。 有什么想法吗?

6
您将如何练习并发和多线程?[关闭]
我一直在阅读有关并发,多线程以及“免费午餐已经结束”的信息。但是我还没有在工作中使用MT的可能性。 因此,我正在寻找有关如何通过练习或参加一些开源项目来获得CPU重度MT练习的建议。 谢谢。 编辑:我对使用MT来执行CPU约束任务的开源项目更感兴趣,或者对使用MT来实现有趣的算法感兴趣,而不是只描述线程,互斥锁和锁之类的工具的书籍或论文,或者MT如何用于具有响应式GUI ...

3
如果Windows上没有线程支持,GCC会死吗?[关闭]
我需要一些意见。GCC一直是一个非常好的编译器,但是最近它失去了“吸引力”。我刚刚发现Windows上没有GCC std::thread支持,由于仍然缺少最激动人心的功能,因此迫使Windows用户使用其他编译器。 但是,为什么GCC确实在Windows下仍然没有线程支持?许可问题?ABI不兼容?(嗯,已经有几个使用多线程的跨平台库:boost,POCO,SDL,wxwidgets等。使用已经存在且已获得MIT / libpng许可的代码来适应这个漏洞而不是发布GCC版本不是很简单吗?没有线程支持?) 最近,通过对编译器的比较,GCC对C ++ 11功能的支持比其他编译器要大,除了在Windows上这不是事实,因为我们仍然缺少原子,互斥体和线程:/ 我想了解更多有关此主题的信息,但我唯一能找到的人是寻求帮助的人,因为: std名称空间中不存在“线程” 从GCC / TDM-GCC的票务跟踪和邮件讨论开始,自2009年以来就一直在寻求线程支持的请求。可能在4年后仍然没有解决方案吗?到底发生了什么事?

8
什么时候需要“成千上万”的线程?
Erlang,Go和Rust都以一种或另一种方式声称它们支持使用廉价的“线程” /协程进行并发编程。在转到FAQ状态: 在同一个地址空间中创建数十万个goroutine是很实际的。 该防锈教程说: 由于创建任务比传统线程便宜得多,因此Rust可以在典型的32位系统上创建数十万个并发任务。 Erlang的文档说: 为了支持具有数十万甚至数百万个进程的Erlang系统,默认的初始堆大小为233个字是非常保守的。 我的问题:哪种应用程序需要这么多并发执行线程?只有最繁忙的Web服务器才能同时接收数千名访问者。当线程/进程的数量远大于物理核心的数量时,我编写的老板/工作调度型应用程序命中率递减。我想这对于数字应用程序可能有意义,但实际上,大多数人将并行性委托给以Fortran / C / C ++编写的第三方库,而不是这些较新一代的语言。

2
虚假的唤醒说明听起来像是一个不值得修复的错误,对吗?
根据维基百科有关虚假唤醒的文章 “即使没有线程向条件变量发出信号,线程也可能从等待状态中唤醒”。 虽然我已经知道了这个“功能”,但是直到同一篇文章中,我才知道真正的原因是什么 “虚假唤醒听起来可能很奇怪,但是在某些多处理器系统上,使条件唤醒完全可预测可能会大大减慢所有条件变量的运行。” 听起来像是一个不值得修复的错误,对吗?

11
被多线程错误困扰
在我管理的新团队中,我们的大部分代码是平台,TCP套接字和http网络代码。所有C ++。其中大多数来自离开团队的其他开发人员。团队中目前的开发人员非常聪明,但从经验来看大多是初级的。 我们最大的问题:多线程并发错误。我们的大多数类库都通过使用某些线程池类而被编写为异步的。类库中的方法通常将长时间运行的任务从一个线程排队到线程池中,然后在另一个线程上调用该类的回调方法。结果,我们有很多涉及错误线程假设的边缘错误。这导致了一些细微的错误,这些错误不仅仅具有关键部分和锁以防止并发问题。 使这些问题更难解决的是,修复尝试通常是不正确的。我发现团队在尝试(或在遗留代码本身中)尝试犯的一些错误包括以下内容: 常见错误#1-通过仅对共享数据进行锁定来解决并发问题,但是忘记了当方法未按预期顺序调用时会发生什么情况。这是一个非常简单的示例: void Foo::OnHttpRequestComplete(statuscode status) { m_pBar->DoSomethingImportant(status); } void Foo::Shutdown() { m_pBar->Cleanup(); delete m_pBar; m_pBar=nullptr; } 因此,现在有了一个错误,其中在OnHttpNetworkRequestComplete发生时可以调用Shutdown。测试人员找到错误,捕获故障转储,并将错误分配给开发人员。他反过来修复了这样的错误。 void Foo::OnHttpRequestComplete(statuscode status) { AutoLock lock(m_cs); m_pBar->DoSomethingImportant(status); } void Foo::Shutdown() { AutoLock lock(m_cs); m_pBar->Cleanup(); delete m_pBar; m_pBar=nullptr; } 除非您意识到还有一个更微妙的边缘情况,否则上面的修补程序看起来不错。如果在调用OnHttpRequestComplete 之前调用Shutdown,会发生什么情况?我的团队拥有的真实示例更加复杂,并且在代码审查过程中很难发现边缘情况。 常见错误#2-通过盲目退出锁来解决死锁问题,等待另一个线程完成,然后重新进入锁-但是没有处理对象只是被另一个线程更新的情况! 常见错误#3-即使对象是引用计数,关闭序列也会“释放”它的指针。但是忘记等待仍在运行的线程释放它的实例。这样,组件将完全关闭,然后在不希望再有任何调用的状态下在对象上调用伪造或较晚的回调。 还有其他边缘情况,但最重要的是: 即使对于聪明人,多线程编程也很难。 当我发现这些错误时,我会花时间与每个开发人员讨论这些错误,以开发更合适的修复程序。但是我怀疑,由于“正确的”解决方案涉及到大量遗留代码,因此他们常常对如何解决每个问题感到困惑。 我们将很快发货,并且我确定我们正在应用的补丁将在即将发布的版本中保留。之后,我们将有一些时间来改善代码库并在需要时进行重构。我们将没有时间重新编写所有内容。而且大多数代码还不错。但是我希望重构代码,以便可以完全避免线程问题。 我正在考虑的一种方法是这种方法。对于每个重要的平台功能,请使用专用的单线程,将所有事件和网络回调整理到其中。与Windows中使用消息循环的COM公寓线程相似。长阻塞操作仍然可以分派到工作池线程,但是完成回调在组件的线程上调用。组件甚至可能共享同一线程。然后,可以在单个线程世界的假设下编写线程中运行的所有类库。 在走这条路之前,如果还有其他标准技术或设计模式来处理多线程问题,我也非常感兴趣。我必须强调-除了描述互斥量和信号量基础知识的书以外的内容。你怎么看? 我也对其他用于重构过程的方法感兴趣。包括以下任何一项: 有关线程周围设计模式的文献或论文。除了互斥量和信号量介绍之外,还有其他内容。我们也不需要大规模的并行性,只需设计对象模型以正确处理来自其他线程的异步事件的方法即可。 …

3
多线程应用程序的UML图
对于单线程应用程序,我喜欢使用类图来概述该应用程序的体系结构。但是,在尝试了解大量的多线程/并发应用程序时,这种类型的图并不是很有用,例如,因为类的不同实例在不同的线程上“处于活动状态”(意味着访问一个实例仅从一个实例中保存)线程继续存在)。因此,类之间的关联并不一定意味着我可以在那些对象上调用方法,而是必须在目标对象的线程上进行该调用。 我在该主题上挖掘过的大多数文献 ,例如Hassan Gomaa的UML设计并发,分布式和实时应用程序,都有一些不错的主意,例如将线程边界绘制到对象图中,但总体而言似乎有点学术性和冗长性真的很有用。 我不想将这些图用作问题域的高级视图,而只是作为我的类/对象,它们之间的相互作用以及我上面提到的线程边界所造成的限制的详细描述。 因此,我想知道: 您发现哪种类型的图对理解多线程应用程序最有帮助? 对经典UML的扩展是否考虑了多线程应用程序的特殊性,例如通过说明 有些对象可能生活在某个线程中,而另一些对象则没有线程亲和性; 对象的某些字段可以从任何线程读取,但只能从一个线程写入。 有些方法是同步的并返回结果,而另一些方法则是异步的,这些方法使请求排队,并例如通过不同线程上的回调返回结果。

7
调试死锁时您会寻找什么?
最近,我一直在从事大量使用线程的项目。我认为我可以设计它们。尽可能使用无状态设计,锁定对一个线程以上需求的所有资源的访问,等等。我在函数式编程中的经验对此提供了极大的帮助。 但是,在阅读别人的线程代码时,我会感到困惑。我现在正在调试死锁,并且由于编码样式和设计与我的个人风格不同,因此我很难看到潜在的死锁情况。 调试死锁时您会寻找什么?

4
是什么阻止了锁上的竞争状况?
我了解什么是数据竞争,以及锁/互斥/信号灯如何防止它们的基础知识。但是,如果锁本身具有“竞赛条件”,会发生什么?例如,可能在同一应用程序中但在不同处理器上运行的两个不同线程尝试在完全相同的时间获取锁。 那会发生什么呢?为防止这种情况该怎么做?这是不可能的,还是完全不可能?还是等待发生的真实比赛条件?

10
状态机与线程
艾伦·考克斯(Alan Cox)曾说过: “计算机是状态机。线程是为无法对状态机进行编程的人的。” 由于直接询问Alan并不是让我谦虚的选择,所以我想在这里问:一个人如何仅使用一个线程和状态机来实现高级语言(例如Java)的多线程功能?例如,如果要执行2个活动(进行计算和执行I / O)并且一个活动可以阻止该怎么办? 使用“仅状态机”方式是否可以替代高级语言中的多线程?

6
多线程:我做错了吗?
我正在开发一个播放音乐的应用程序。 在回放期间,通常情况需要在单独的线程上发生,因为它们需要同时发生。例如,一个和弦需要的音符一起被听到,所以每个人都分配了其自己的线程中进行播放(编辑澄清:调用note.play()冻结线程,直到音符播放完毕,这就是为什么我需要三个独立线程以同时听到三个音符。) 这种行为在播放音乐时会创建许多线程。 例如,考虑一段音乐,该音乐具有短旋律和较短的伴随和弦进行。整个旋律可以在单个线程上弹奏,但是该进程需要三个线程才能弹奏,因为其每个和弦都包含三个音符。 因此,用于播放进度的伪代码如下所示: void playProgression(Progression prog){ for(Chord chord : prog) for(Note note : chord) runOnNewThread( func(){ note.play(); } ); } 因此,假设进程有4个和弦,并且我们演奏了两次,则我们打开3 notes * 4 chords * 2 times= 24个线程。这只是播放一次。 实际上,它在实践中效果很好。我没有注意到任何明显的延迟或由此导致的错误。 但是我想问一下这是正确的做法,还是我做的事情根本上是错误的。每次用户按下按钮时创建这么多线程是否合理?如果没有,我该怎么做?

3
为什么通常首选多线程来提高性能?
此问题是从Stack Overflow 迁移而来的,因为可以在Software Engineering Stack Exchange上回答。 迁移 6年前。 我有一个问题,那就是为什么程序员似乎总体上喜欢并发和多线程程序。 我在这里考虑2种主要方法: 一种基本上基于信号的异步方法,或者只是许多论文和语言(例如,新的C#5.0)所调用的一种异步方法,以及一个用于管理管道策略的“伴侣线程” 并发方法或多线程方法 我只是说,我正在考虑这里的硬件和最坏的情况,并且我自己已经测试了这两种范例,异步范例是赢家,因为我不明白为什么人们有90%的情况当他们想要加快工作速度或充分利用他们的资源时,谈论多线程。 我已经在一台旧计算机上使用Intel四核测试了多线程程序和异步程序,该英特尔四核在CPU内不提供内存控制器,内存完全由主板管理,在这种情况下,性能令人震惊。多线程应用程序,即使是数量相对较少的线程(例如3-4-5)也可能是一个问题,该应用程序没有响应,并且运行缓慢且令人不快。 另一方面,一种好的异步方法可能不会更快,但也并不坏,我的应用程序只是等待结果并且不会挂起,它具有响应能力,并且伸缩性更好。 我还发现,线程世界中的上下文更改在现实世界中并不是那么便宜,实际上它相当昂贵,尤其是当您有两个以上的线程需要循环和相互交换来计算时。 在现代CPU上,集成的内存控制器的情况并没有什么不同,但我的观点是x86 CPU基本上是一台串行计算机,并且该内存控制器的工作方式与在主板上带有外部内存控制器的旧计算机的工作方式相同。 。上下文切换仍然是我应用程序中的一个相关成本,并且集成了内存控制器或较新的CPU具有2个以上内核的事实对我来说并不便宜。 因为我所经历的并发方法在理论上是好的,但在实践中却不是那么好,由于硬件强加了内存模型,很难很好地利用这种范式,而且还引入了很多问题,从使用到使用我的数据结构连接到多个线程。 同样,这两种范式都不能提供任何安全性,而只是在某个时间点完成任务或工作时,从功能的角度来看,它们确实非常相似。 根据X86内存模型,为什么大多数人建议对C ++使用并发,而不仅仅是异步方法?另外,为什么不考虑环境切换可能比计算本身更昂贵的计算机的最坏情况呢?

9
多线程同步面试问题:给定m个线程,找到n个单词
有没有办法可以从具有多个线程而不是单个线程的解决方案中受益于此问题? 在一次采访中,我被要求使用多个线程解决问题。在我看来,多个线程毫无益处。 这是问题所在: 给您一个段落,其中包含n个单词,给您m个线程。您需要做的是,每个线程应打印一个单词并将控制权交给下一个线程,这样每个线程将继续打印一个单词,以防最后一个线程到来,它应调用第一个线程。重复打印,直到段落中所有单词都打印完为止。最后,所有线程都应正常退出。将使用哪种同步? 我强烈感到我们无法利用这里的线程,但相信面试官正在尝试评估我的同步技能。我是否在此问题中缺少使多个线程有价值的内容? 无需编写代码,只需提出一些想法即可。我将自己执行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.