简体   繁体   English

多线程和互斥

[英]Multithreading and mutexes

I'm currently beginning development on an indie game in C using the Allegro cross-platform library. 我目前正在使用Allegro跨平台库开始在C中的独立游戏开发。 I figured that I would separate things like input, sound, game engine, and graphics into their own separate threads to increase the program's robustness. 我认为我会将输入,声音,游戏引擎和图形等内容分离到各自独立的线程中,以提高程序的稳健性。 Having no experience in multithreading whatsoever, my question is: 我没有多线程经验,我的问题是:

If I have a section of data in memory (say, a pointer to a data structure), is it okay for one thread to write to it at will and another to read from it at will, or would each thread have to use a mutex to lock the memory, then read or write, then unlock? 如果我在内存中有一段数据(比如指向数据结构的指针),一个线程可以随意写入它,另一个线程可以随意读取,或者每个线程都必须使用互斥锁锁定内存,然后读取或写入,然后解锁?

In particular, I was thinking about the interaction between the game engine and the video renderer. 特别是,我在考虑游戏引擎和视频渲染器之间的交互。 (This is in 2D.) My plan was for the engine to process user input, then spit out the appropriate audio and video to be fed to the speakers and monitor. (这是2D。)我的计划是让引擎处理用户输入,然后吐出适当的音频和视频以馈送到扬声器和监视器。 I was thinking that I'd have a global pointer to the next bitmap to be drawn on the screen, and the code for the game engine and the renderer would be something like this: 我以为我有一个全局指针指向要在屏幕上绘制的下一个位图,游戏引擎和渲染器的代码将是这样的:

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);
    }

  }

This seems unstable... maybe something would happen in the call to al_clone_bitmap but I am not quite certain how to handle something like this. 这似乎不稳定......也许在调用al_clone_bitmap时会发生一些事情,但我不太确定如何处理这样的事情。 I would use a mutex on the bitmap, but mutexes seem like they take time to lock and unlock and I'd like both of these threads (especially the game engine thread) to run as fast as possible. 我会在位图上使用互斥锁,但互斥锁似乎需要时间来锁定和解锁,我希望这两个线程(尤其是游戏引擎线程)尽可能快地运行。 I also read up on something called a condition, but I have absolutely no idea how a condition would be applicable or useful, although I'm sure they are. 我还读了一个叫做条件的东西,但我完全不知道条件是如何适用或有用的,尽管我确定它们是。 Could someone point me to a tutorial on mutexes and conditions (preferably POSIX, not Windows), so I can try to figure all this out? 有人能指点我一个关于互斥和条件的教程(最好是POSIX,而不是Windows),所以我可以尝试解决所有这些问题吗?

If I have a section of data in memory (say, a pointer to a data structure), is it okay for one thread to write to it at will and another to read from it at will 如果我在内存中有一段数据(例如,指向数据结构的指针),一个线程可以随意写入它而另一个线程可以随意读取它

The answer is "it depends" which usually means "no". 答案是“它取决于”,通常意味着“不”。

Depending on what you're writing/reading, and depending on the logic of your program, you could wind up with wild results or corruption if you try writing and reading with no synchronization and you're not absolutely sure that writes and reads are atomic. 根据您正在编写/阅读的内容,并且根据程序的逻辑,如果您尝试在没有同步的情况下进行写入和读取,并且您不能完全确定写入和读取是原子的,那么您可能会遇到疯狂的结果或损坏。

So you should just use a mutex unless: 所以你应该使用互斥锁,除非:

  1. You're absolutely sure that writes and reads are atomic, and you're absolutely sure that one thread is only reading (ideally you'd use some kind of specific support for atomic operations such as the Interlocked family of functions from WinAPI). 您完全确定写入和读取是原子的,并且您完全确定一个线程只是读取(理想情况下,您将使用某种特定的原子操作支持,例如WinAPI中的Interlocked系列函数)。
  2. You absolutely need the tiny performance gain from not locking. 你绝对需要不锁定的微小性能提升。

Also worth noting that your while (using); 还值得注意的是你的while (using); construct would be a lot more reliable, correct, and would probably even perform better if you used a spin lock (again if you're absolutely sure you need a spin lock, rather than a mutex). 如果使用自旋锁 ,那么构造将更加可靠,正确,并且甚至可能表现更好(如果你绝对确定需要自旋锁,而不是互斥锁,那么)。

The tool that you need is called atomic operations which would ensure that the reader thread only reads whole data as written by the other thread. 您需要的工具称为原子操作 ,它将确保读取器线程只读取由另一个线程写入的整个数据。 If you don't use such operations, the data may only be read partially, thus what it read may may make no sense at all in terms of your application. 如果您不使用此类操作,则数据可能只能部分读取,因此根据您的应用程序读取的内容可能完全没有意义。

The new standard C11 has these operations, but it is not yet widely implemented. 新标准C11具有这些操作,但尚未广泛实施。 But many compilers should have extension that implement these. 但是许多编译器应该具有实现这些的扩展。 Eg gcc has a series of builtin functions that start with a __sync prefix. 例如,gcc有一系列以__sync前缀开头的内置函数。

There are a lot of man pages in 'google'. 'google'中有很多手册页。 Search for them. 搜索他们。 I found http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html in a few search minutes: 我在几分钟内找到了http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html

Besides, begin with a so little example, increasing difficulty. 此外,从一个很小的例子开始,增加难度。 Firstable with threads creation and termination, threads returns, threads sincronization. Firstable与线程创建和终止,线程返回,线程sincronization。 Continue with posix mutex and conditions and understand all these terms. 继续使用posix互斥和条件并理解所有这些术语。

One important documentation feed is linux man and info pages. 一个重要的文档提要是linux man和info页面。

Good luck 祝好运

If I have a section of data in memory (say, a pointer to a data structure), is it okay for one thread to write to it at will and another to read from it at will, or would each thread have to use a mutex to lock the memory, then read or write, then unlock? 如果我在内存中有一段数据(比如指向数据结构的指针),一个线程可以随意写入它,另一个线程可以随意读取,或者每个线程都必须使用互斥锁锁定内存,然后读取或写入,然后解锁?

If you have section of data in memory where two different threads are reading and writing this is called the critical section and is a common issue of the consumer and producer. 如果你在内存中有两个不同线程正在读写的数据部分,这称为临界部分,这是消费者和生产者的常见问题。

There are many resources that speak to this issue: 有许多资源可以解决这个问题:

But yes if you are going to be using two different threads to read and write you will have to implement the use of mutexes or another form of locking and unlocking. 但是,如果您要使用两个不同的线程进行读写,则必须实现互斥锁的使用或其他形式的锁定和解锁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM