3

我目前正在使用 Allegro 跨平台库开始开发 C 语言独立游戏。我想我会将诸如输入、声音、游戏引擎和图形之类的东西分离到它们自己独立的线程中,以提高程序的健壮性。没有任何多线程经验,我的问题是:

如果我在内存中有一段数据(例如,指向数据结构的指针),一个线程可以随意写入它,另一个线程随意读取它,还是每个线程都必须使用互斥锁锁定内存,然后读取或写入,然后解锁?

特别是,我在考虑游戏引擎和视频渲染器之间的交互。(这是二维的。)我的计划是让引擎处理用户输入,然后将适当的音频和视频输出到扬声器和监视器。我在想我会有一个指向要在屏幕上绘制的下一个位图的全局指针,游戏引擎和渲染器的代码将是这样的:

ALLEGRO_BITMAP *nextBitmap;
boolean using;

void GameEngine ()
  {

  ALLEGRO_BITMAP *oldBitmap;

  while (ContinueGameEngine())
    {
    ALLEGRO_BITMAP *bitmap = al_create_bitmap (width, height);
    MakeTheBitmap (bitmap);
    while (using) ; //The other thread is using the bitmap. Don't mess with it!
    al_destroy_bitmap (nextBitmap);
    nextBitmap = bitmap;
    }

  }

void Renderer ()
  {

  while (ContinueRenderer())
    {
    ALLEGRO_BITMAP *bitmap = al_clone_bitmap (nextBitmap);
    DrawBitmapOnScreen (bitmap);
    }

  }

这似乎不稳定......也许在调用时会发生一些事情,al_clone_bitmap但我不太确定如何处理这样的事情。我会在位图上使用互斥锁,但互斥锁似乎需要时间来锁定和解锁,我希望这两个线程(尤其是游戏引擎线程)尽可能快地运行。我还阅读了一种称为条件的东西,但我完全不知道条件将如何适用或有用,尽管我确信它们是。有人可以指点我关于互斥锁和条件的教程(最好是 POSIX,而不是 Windows),这样我就可以尝试解决所有这些问题吗?

4

4 回答 4

1

如果我在内存中有一段数据(例如,指向数据结构的指针),一个线程随意写入它而另一个线程随意读取它是否可以?

答案是“视情况而定”,这通常意味着“否”。

根据您正在写入/读取的内容以及程序的逻辑,如果您尝试在不同步的情况下进行写入和读取,并且您不确定写入和读取是否是原子的,则可能会导致疯狂的结果或损坏.

所以你应该只使用互斥锁,除非:

  1. 您绝对确定写入和读取是原子的,并且您绝对确定一个线程只在读取(理想情况下,您会使用某种特定的对原子操作的支持,例如InterlockedWinAPI 中的函数族)。
  2. 您绝对需要从不锁定中获得微小的性能提升。

还值得注意的是,如果您使用自旋锁while (using);,您的构造会更加可靠、正确,甚至可能性能更好(同样,如果您绝对确定需要自旋锁,而不是互斥锁)。

于 2012-12-20T07:30:24.760 回答
1

您需要的工具称为原子操作,它将确保读取器线程仅读取另一个线程写入的整个数据。如果您不使用此类操作,则可能仅读取部分数据,因此读取的内容可能对您的应用程序毫无意义。

新标准 C11 有这些操作,但尚未广泛实施。但是许多编译器应该具有实现这些的扩展。例如 gcc 有一系列以__sync前缀开头的内置函数。

于 2012-12-20T08:17:38.030 回答
0

“google”中有很多手册页。寻找他们。我在几分钟内找到了http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html :

此外,从一个很小的例子开始,增加了难度。首先可以创建和终止线程,线程返回,线程sincronization。继续使用 posix 互斥锁和条件并理解所有这些术语。

一个重要的文档提要是 linux 手册和信息页面。

祝你好运

于 2012-12-20T07:29:44.197 回答
0

如果我在内存中有一段数据(例如,指向数据结构的指针),一个线程可以随意写入,另一个线程可以随意读取,还是每个线程都必须使用互斥锁锁定内存,然后读取或写入,然后解锁?

如果您在内存中有两个不同线程正在读取和写入的数据部分,则这称为临界区,并且是消费者和生产者的常见问题。

有很多资源可以解决这个问题:

但是是的,如果您要使用两个不同的线程来读取和写入,则必须实现互斥锁或其他形式的锁定和解锁的使用。

于 2018-02-11T19:39:00.023 回答