【发布时间】:2020-03-29 10:10:50
【问题描述】:
编辑2:要明确我的问题是我正在努力编写代码来阻止和恢复线程来做一些工作(在这种情况下,读取一些文件)。
编辑 3:添加了 void Loader::RequestToLoadRegion(Region ®ion) 的函数定义。
我想在我的游戏中创建一个基本的流媒体系统。我需要一个线程来读取大部分时间会被阻塞并不时唤醒的游戏文件。这是我当前设计的工作原理。
每当玩家接近未加载到 RAM 中的世界区域时, 游戏向(唯一)Loader 对象发送请求以加载该区域(Loader 类代表流系统)。 每个区域都有一个与之关联的文件列表,这些文件将被读取以创建游戏数据并将其加载到 RAM 中。
加载分两步完成:
- 第 1 步:读取所有文件并将其内容推送到队列中,
- 第 2 步:处理存储在此队列中的原始文件数据。
Loader 对象使用 Reader 对象读取所有文件并将其内容推送到上述队列中。在 Loader 的构造函数中,构造了 Reader 对象,该对象启动了一个线程,该线程将用于读取文件。但是,这个读取线程大部分时间都会被阻塞,只有当 Loader 收到加载新区域的请求时才会被 Loader 唤醒。
在每一帧开始时,Loader 将获得控制权并检查其当前状态,无论是否加载。如果它处于加载状态,那么它将尝试访问受互斥体保护的队列。如果它从队列中获得一个项目,它将处理它并将控制权交还给游戏。队列中的下一项将在下一帧处理,以此类推,直到区域加载完成。
我知道如何使用互斥锁来实现这部分。但是,我有一些麻烦要保持读取线程被阻塞并在加载请求到达时唤醒它。我已经学会了如何将 std::condition_variable 用于基本程序,我目前的解决方案如下:
- 在创建加载程序后,它会锁定一个互斥体,以便读取线程保持阻塞状态。
- 当游戏向 Loader 发送请求时,后者将 Reader 的标志 (m_canRead) 设置为 true,并使用条件变量调用 notify_one() 以唤醒读取线程。
-
当读取线程即将读取文件时,它会调用 m_loader.OnStartReading() 以便 Loader 锁定 m_canReadMutex 互斥锁。然后控制权返回给读取文件的阅读器。
我在这个设计中遇到的最大问题是,我了解到您通常会在短时间内锁定互斥锁,并且通常将它与 std::lock_guard 一起使用,这样如果发生异常,互斥锁就会被解锁。
// This is the function ran by the reading thread
// m_readingThread = std::thread(&Reader::Run, this);
void Reader::Run() {
while (true) {
{
std::unique_lock<std::mutex> ul(m_canReadMutex);
m_canReadCondVar.wait(ul, [this](){ return m_quit || m_canRead; });
// Determine the cause of the wake up
if (m_quit) { // Does the game wants to quit? We break out of
break; // the loop to reach the end of the Run() function
} // that way we can join() the reading thread.
// If control reaches this line, it means the thread was awaken by
// a load request and can read. The closing bracket "will run the destructtor"
// of the std::unique_lock to unlock the mutex.
}
{ // When control reaches this scope, it means m_canRead is true.
m_loader.OnStartReading(); // will lock the mutex m_canReadMutex
ReadFiles();
}
}// end-while (true)
}// end-function void Run()
void Reader::ReadFiles() {
/* Read all the files and push data into the queue */
}
void Loader::OnStartReading() {
m_canReadMutex.lock();
}
// This function unlocks the mutex and wake up the reading thread.
void Loader::RequestToLoadRegion(Region ®ion) {
/* Get the list of files associated to the region */
m_canReadMutex.unlock();
m_reader.m_canRead = true; // Set the flag so the predicate in the reader's wait() evaluates to true
m_canReadCondVar.notify_one(); // Wake up the reader thread
}
【问题讨论】:
-
我不确定你的问题是什么,即你的类/意图是复杂和模糊的,但是当锁定一个条件变量时,它持有的互斥锁在启动等待时被解锁。
-
流系统由一个单例加载器表示。该对象使用一个 Reader 对象,该对象启动一个线程从磁盘读取文件,而主线程运行游戏循环。我的问题是编写停止并启动读取线程的代码。
标签: c++ multithreading