多线程和互斥

时间:2012-12-20 07:09:45

标签: c multithreading allegro5

我目前正在使用Allegro跨平台库开始在C中的独立游戏开发。我认为我会将输入,声音,游戏引擎和图形等内容分离到各自独立的线程中,以提高程序的稳健性。没有任何多线程经验,我的问题是:

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

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

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 个答案:

答案 0 :(得分:1)

  

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

答案是“它取决于”通常意味着“不”。

根据您正在编写/阅读的内容,并且根据您的程序的逻辑,如果您尝试在没有同步的情况下进行写入和阅读,并且您不能完全确定写入和写入,那么您可能会遇到疯狂的结果或损坏。读取是原子的。

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

  1. 您完全确定写入和读取是原子的,并且您完全确定一个线程只是读取(理想情况下,您将对Interlocked系列等原子操作使用某种特定支持来自WinAPI的功能。)
  2. 你绝对需要通过不锁定来获得微小的性能提升。
  3. 另外值得注意的是,你的while (using);构造会更可靠,更正确,如果使用spin lock,甚至可能表现更好(如果你绝对确定需要旋转的话)锁定,而不是互斥锁。)

答案 1 :(得分:1)

您需要的工具称为原子操作,这将确保读取器线程只读取由另一个线程写入的整个数据。如果您不使用此类操作,则数据可能只能部分读取,因此根据您的应用程序读取的数据可能完全没有意义。

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

答案 2 :(得分:0)

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

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

一个重要的文档提要是linux man和info pages。

祝你好运

答案 3 :(得分:0)

  

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

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

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

但是,如果你打算使用两个不同的线程进行读写,则必须实现互斥锁的使用或其他形式的锁定和解锁。