当双缓冲的数据这是由于被线程之间共享执行指针交换,我使用一个系统,其中一个线程从一个缓冲器读出,一个线程从另一个缓冲器读出和读出从第一个缓冲区。麻烦的是,我将如何实现指针交换?我需要使用关键部分吗?没有互锁功能可以实际交换数值。我不能让线程从缓冲区读取一个,然后开始从缓冲区读取两个,在读取的过程中,这将是appcrash,即使其他线程没有开始写入。在双缓冲的多线程系统
我在Visual Studio Ultimate 2010 RC的Windows上使用本机C++。
当双缓冲的数据这是由于被线程之间共享执行指针交换,我使用一个系统,其中一个线程从一个缓冲器读出,一个线程从另一个缓冲器读出和读出从第一个缓冲区。麻烦的是,我将如何实现指针交换?我需要使用关键部分吗?没有互锁功能可以实际交换数值。我不能让线程从缓冲区读取一个,然后开始从缓冲区读取两个,在读取的过程中,这将是appcrash,即使其他线程没有开始写入。在双缓冲的多线程系统
我在Visual Studio Ultimate 2010 RC的Windows上使用本机C++。
为什么不能使用InterlockedExchangePointer?
编辑:好吧,我给你说的话,现在,IEP实际上不换2点彼此生活的指针,因为它只能通过引用,采用一个单值。
如果您是InterlockedExchangePointer,则只能在呼叫中实际影响一个指针。这意味着为了交换所有三个指标,我需要三个电话 - 在中间留下一个空白。 InterlockedExchangePointer实际上是一个用词不当,它只会给给定值的给定指针。我预计它会交换一对指针(正是出于这个原因)。即使它的确如此工作,但如果不暂停这两个线程来执行更新,我仍然无法实际使用它,这是我真正想避免的。 – DeadMG 2010-02-15 20:39:23
@DeadMG:'buf1 = InterlockedExchangePointer(&buf2,buf1);'如果你从当前使用buf1的线程调用它,我认为它会做你想做的。但我不完全确定你的意思是“所有三个指针”。 – Dan 2010-02-15 22:45:30
我有一个来自渲染的缓冲区,一个来自游戏逻辑的缓冲区(所以它们都可以读取缓冲区),然后一个缓冲区以供游戏逻辑写入。问题是您调用的等价操作符不一定是原子 - InterlockedExchangePointer和buf1 =之间存在差距。即使没有,在这种情况下,仍然没有机制来确保我不在渲染过程中。 我认为在另一个答案中描述的读写互斥解决方案可能是最好的。 – DeadMG 2010-02-15 23:05:20
使用关键部分是可以接受的方式。只需在你的指针操作/缓冲区读/写代码周围共享一个CRITICAL_SECTION
对象,并在该对象上调用EnterCriticalSection
和LeaveCriticalSection
。尝试尽快完成关键部分,尽可能在关键部分之外留下尽可能多的代码。
即使你使用双联锁交流技巧,你仍然需要一个临界区或东西同步线程,所以还不如将其用于这个目的了。
您必须构建自己的函数来交换使用信号量或临界区的指针来控制它。需要将相同的保护添加到指针的所有用户,因为读取正在被修改的指针的任何代码是不好的。
管理这个的一种方法是让所有指针操作逻辑在锁的保护下工作。
请参阅我最初设计的线程,以使它们完全异步,并且不需要在常规操作中进行任何同步。但是,因为我在线程池中以每个对象为基础执行操作,所以如果给定的对象由于当前正在同步而不可读,那么在等待时我可以再做一次。从某种意义上说,我可以同时等待和操作,因为我有很多线索可以解决。
创建两个关键部分,每个线程一个。 渲染时,按住渲染暴击部分。另一个线程仍然可以做到它喜欢的其他爆击部分。使用TryEnterCriticalSection,如果它被保留,则返回false,并将该对象添加到列表中以稍后重新呈现。这应该允许我们继续渲染,即使给定的对象当前正在更新。 更新时,同时保留两个暴击部分。 在进行游戏逻辑的同时,保持游戏逻辑暴击部分。如果已经存在,那就没有问题了,因为我们的线程比实际的处理器多。所以如果这个线程被阻塞,那么另一个线程将只使用CPU时间,这不需要管理。
您还没有提及您的Windows平台限制,但是如果您不需要与Windows Server 2003或客户端上的Vista相比较旧版本的兼容性,则可以使用InterlockedExchange64()函数来交换64位值。通过将两个32位指针打包为64位对结构,可以有效地交换两个指针。
有通常的Interlocked * variantions; InterlockedExchangeAcquire64(),InterlockedCompareExchange64()等...
如果你需要运行,比如XP,我会去一个关键部分。当争用的可能性很低时,它们表现相当好。
我很乐意考虑不在XP上运行。但是,它并没有解决交换中间渲染指针的问题。 – DeadMG 2010-02-15 21:24:40
这听起来像是一个读写器互斥类型的问题。
假设您有两个缓冲区B1和B2,并且您有两个线程T1和T2。如果T1正在使用B1而T2正在使用B2,则可以。 “使用”是指读取和/或写入缓冲区。然后在某个时候,缓冲区需要交换,以便T1使用B2,而T2使用B1。你必须小心的是,交换是在两个线程都不访问缓冲区的情况下完成的。
假设您只使用了一个简单的互斥锁。 T1可以获得互斥体并使用B1。如果T2想要使用B2,它必须等待互斥锁。当T1完成时,T2将解除阻塞并与B2一起工作。如果任一线程(或某个第三方线程)想要交换缓冲区,则它也必须采用互斥锁。因此,只使用一个互斥量序列化访问缓冲区 - 不太好。
如果您改用读写器互斥锁,它可能会更好。 T1可以获得对互斥锁的读锁,并使用B1。 T2也可以获得对互斥锁的读锁,并使用B2。当其中一个线程(或第三方线程)决定交换缓冲区时,它将不得不对互斥锁执行写入锁定。直到没有更多的读锁,它将无法获得写锁。此时,它可以交换缓冲区指针,知道没有人使用任何一个缓冲区,因为当互斥锁上存在写入锁定时,所有尝试读取锁定的操作都将被阻止。
一个有趣的解决方案 - 几乎和我以前一样,除了更清洁。但是,我无法在MSDN上找到关于这种互斥体的任何文档。它们是WinAPI的固有组成部分,还是我必须自己编写代码? – DeadMG 2010-02-15 23:02:37
打败我。我谷歌'读者作家互斥窗口',并发现这一点:http://msdn.microsoft.com/en-us/magazine/cc163599.aspx - 有帮助吗?谷歌没有'windows'来读理论...... – Dan 2010-02-16 01:52:28
如果传入数据的顺序很重要,那么仍然需要同步。无论读者/写者互斥,阅读者在继续之前都必须等待新的数据到达。 – 2011-03-25 15:40:19
你是什么意思?“没有互锁功能可以实际交换值。”?为什么你不能使用这些功能? – AndiDog 2010-02-15 20:33:20