2012-02-15 148 views
0

如果有2个线程试图同时写入同一个对象的代码,我的理解是它不会产生任何编译时错误,这是调试多线程的部分原因计划是如此困难。但是这会产生运行时错误/异常吗?调试多线程程序

任何人都可以提出任何好的多线程调试技术?

谢谢。

回答

1

从两个或多个不同的线程中访问同一个对象不会在运行时或调试器中产生错误,但它很可能会以您不打算的方式绕过对象。

在多线程环境中安全地处理它的方法是使用互斥锁和信号量。 对于互斥锁,请检查wikipedia link

互斥锁通常用于当您想限制一次只有一个线程访问对象的情况。

另一方面,信号量是一个更一般的情况(互斥量实际上是一个信号量的特例),它有一个计数器,每个线程将根据信号量的激活/停用而增加/减少。当信号量达到0时,它将锁定自己和导致它的线程。有关信号量的更多信息,请查看wikipedia page

如果您需要更具体的建议,那么我建议您向我们提供有关您所使用的操作系统和/或您所使用的API的信息,因为任何与线程(互斥锁,信号量等)是操作系统特定的

+0

Lefteris调试多线程代码,感谢您的回复。我正在使用Boost库,并试图在Windows和Linux上创建一个跨平台的应用程序。我对多线程编程相当陌生,对于不同的通信技术我很困惑。 互斥和信号灯如你所说,我也听说过使用同步消息队列。只是想知道是否有任何“标准”方法。 谢谢。 – 2607 2012-02-15 05:57:49

+0

这就是我想要实现的。我有一个M对象的向量,每个对象都有N个成员变量。有X个线程,每个线程可以访问矢量内任何对象的任何成员变量。我试图达到这个目标,并且也有最低限度的关键部分,即每次尽可能少的阻止。谢谢。 – 2607 2012-02-15 05:59:15

+0

如果你想访问是独立的muttualy,那么当你必须使用N个互斥锁时,只有一个线程可以访问N个成员变量之一。我不熟悉boost库,但我相信它具有互斥功能,对吧? – Lefteris 2012-02-15 06:25:50

1

两个不同的线程同时写入单个对象或资源会破坏它,这个问题是一个竞争条件。在多线程程序中,竞态条件既不是编译时错误,也不是运行时错误/异常。竞争条件是管理共享资源,即进程间通信的软件缺陷,并且因为它们破坏幕后数据而令人讨厌。多次运行相同的程序将导致输出结果是预期结果,而在其他时间不是预期结果。

使用互斥排除线程中的竞争条件。如果只有一个对象或资源可用,则使用互斥锁,例如LCD显示器或单个对象,否则如果有多个使用信号量,则有一个示例是四个USB端口。资源是数据和设备。数据是变量,对象,数据结构等。设备是LCD显示器,打印机,USB端口等。

将程序视为顺序单线程并决定需要完成的分离任务可以节省麻烦更多的时间调试。字处理器是一个多线程程序,由几个线程组成。线程的想象示例是:读取文本文件,显示文本,保存文本文件,并可能每5分钟运行一次自动保存。线程应该是可以执行的动作,并注意文字处理器中的所有线程都将文本作为资源。

如果您已经拥有代码或检查值,请在每个线程中的对象之前和之后使用printf语句而不是cout。查看printf的原因,而不是cout here

所有操作系统都有进程间通信,但API不同。 Linux使用POSTIX API,Windows使用Win32或Windows API,但使用方法相同。

阅读材料 http://drdobbs.com/cpp/199200938?pgno=1

^-Summarized一些文章到写着什么

0

它可能会或可能不会的。大多数线程标准的并发修改都是基于UB的,所以他们不能保证会发生什么。通常,对于简单类型,其中一个或另一个写入将“赢”。 (有些平台可以保证对齐,简单的类型。)对于复杂的类型,您可能会撕裂并以“中间值”结束。

并发写入通常不是你有,虽然问题的类型。更常见的情况是重叠读取 - 修改 - 写入操作。例如,考虑尝试将一个项目添加到同一个队列或链接列表的两个线程。当你添加一个项目到一个链表时,可能会有一段时间,链接列表被“破坏”,并且如果另一个线程在链接列表被破坏的时候访问链接列表(在修改过程中,当它部分完成时),事情可以爆炸。

添加项目到链表的头通常涉及这样的:

object->next = head->next; 
head = object; 

如果另一个线程试图对象的第一行完成后,但在第二行开始之前添加到链接列表,结果不会很漂亮。

1

如果你在Linux或OS X,那么你可以使用的工具Valgrind的(hellgrind或DRD)一个检测某些内存访问的线程,而相应的互斥。

但是这不是万无一失的,我不会依靠它来捕捉你所有的问题..很有可能任何共享资源。

0

似乎没有人回答了如何实时调试多线程代码,这真的很难。只有非常短的延迟才会使程序的行为有所不同,并且只有在某些竞争状况发生时才会发生错误。这只能通过非常快速的跟踪来调查,因为Visual Studio的速度太慢了。更糟的是,当两个线程同时调用跟踪方法时,trace方法变得非常慢。

这是很容易给自己的,非阻塞(!)跟踪写入到内存中。只需将信息写入环形缓冲区即可。我的C++不够好,但在C#代码将是这个样子:

const int maxMessages = 0x100; 
const int indexMask = maxMessages-1; 
string[] messages = new string[maxMessages]; 
int messagesIndex = -1; 

public void Trace(string message) { 
    int thisIndex = Interlocked.Increment(ref messagesIndex) & indexMask; 
    messages[thisIndex] = message; 
} 

这种方法也收集线程和定时信息,并输出跟踪好听点是在一个更详细的描述: CodeProject上:实时1