- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
目前我正在为在线游戏开发服务器,并决定将其实现为多线程应用程序。
我有一个实现 while
的主线程循环抽象地从套接字获取数据。
std::vector<std::thread> games_threads;
int start(int game_id) {
std::this_thread::sleep_for(std::chrono::seconds(10));
return end(game_id);
}
int end(int game_id) {
// some other conditions for turn end
return start(game_id);
}
int main() {
// socket implmementation
while(1) {
Message msg = socket.get_data();
switch(msg->action) {
case GAME_START:
std::thread game_thread(start, create_game());
game_thread.detach();
games_threads.push_back(game_thread);
break;
case TURN_END:
std::thread game_thread(end, msg->get_game());
game_thread.detach();
games_threads.push_back(game_thread);
break;
}
}
}
start()
方法。然后在等待 10 秒通话后
end()
实现转弯结束的方法。
end()
方法调用
start()
.
TURN_END
)。 最佳答案
与其说多线程是一种不好的方法,不如说是您的具体实现不正确。
调用start()
函数或 end()
函数将永远不会返回,因为它们每个都以永无止境的递归方式相互调用。这已经很糟糕了,因为随着您深入到函数调用中,您的堆栈将被填满。
但除此之外,当您调用 GAME_START
时,您的主循环会启动一个新线程。这个新线程进入了它的“永远”start()<-->end()
环形。 “OK”到目前为止,但是当TURN_END
被称为你的主要 循环调用 end()
直接,因此您的主循环现在也永远进入 start()<-->end()
环形。现在这意味着您的主线程和“工作”线程都被锁定在这些不返回的循环中 - 因此无法从您的套接字处理更多消息。
我建议您的主循环使用 condition variable向您的工作循环发出信号以强制进行新的转弯。
我不太确定用什么来替换你的 start()<-->end()
递归循环,因为我不清楚这是要达到什么目的。但可能是 timer class可能在这里工作(这个例子是我在谷歌找到的第一个例子)
使用标准输入的完整示例
这里的 start 函数实现了一个线程循环,而不是重复调用 end/start... 当你输入 end
时游戏 ID 1 也会结束。其他比赛照常进行。输入exit
所有游戏退出
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <algorithm>
#include <atomic>
#include <chrono>
#include <condition_variable>
std::vector<std::thread> games_threads;
std::condition_variable cv;
std::mutex cv_m;
int the_game_id = 0;
int start(int id) {
int game_id = id;
bool running = true;
while (running)
{
std::unique_lock<std::mutex> lk(cv_m);
auto now = std::chrono::system_clock::now();
std::cout << "THREAD " << game_id << ": Waiting for turn..." << std::endl;
// Wait for the signal to end turn only if the game ID is for us.
if(cv.wait_until(lk, now + std::chrono::seconds(10), [&game_id](){return (the_game_id == game_id || the_game_id == -1);}))
{
// Condition var signalled
if (the_game_id == -1)
{
std::cout << "THREAD" << game_id << ": end game - exit" << std::endl;
running = false;
}
else
{
std::cout << "THREAD" << game_id << ": turn end forced" << std::endl;
// Reset the game ID so we don't keep triggering
the_game_id = 0;
}
}
else
{
// 10 second timeout occured
std::cout << "THREAD" << game_id << ": 10 seconds is up, end turn" << std::endl;
}
}
std::cout << "THREAD" << game_id << ": ended" << std::endl;
return 1;
}
int main() {
// pretend socket implmementation - using stdin
int id = 1;
bool done = false;
while(!done) {
std::string cmd;
std::getline(std::cin, cmd);
if (cmd == "start")
{
std::cout << "starting..." << std::endl;
games_threads.push_back({ std::thread( [&id](){ return start(id++); } ) });
}
else if (cmd == "end")
{
std::cout << "ending..." << std::endl;
// Notify game ID 1 to end turn - (but in reality get the ID from the message)
the_game_id = 1;
cv.notify_all();
}
else if (cmd == "exit")
{
std::cout << "exiting all threads..." << std::endl;
// Notify game ID 1 to end turn
the_game_id = -1;
cv.notify_all();
done = true;
}
}
// Tidyup threads
for (auto &th : games_threads)
{
if (th.joinable())
{
th.join();
}
}
}
> start
starting...
THREAD 1: Waiting for turn...
> start
starting...
THREAD 2: Waiting for turn...
> start
starting...
THREAD 3: Waiting for turn...
> end
ending...
THREAD1: turn end forced
THREAD 1: Waiting for turn...
THREAD2: 10 seconds is up, end turn
THREAD 2: Waiting for turn...
THREAD3: 10 seconds is up, end turn
THREAD 3: Waiting for turn...
THREAD1: 10 seconds is up, end turn
THREAD 1: Waiting for turn...
> exit
exiting all threads...
THREAD1: end game - exit
THREAD1: ended
THREAD2: end game - exit
THREAD2: ended
THREAD3: end game - exit
THREAD3: ended
关于c++ - 在主线程之外的计时器或命令上销毁/替换线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59450723/
有人可以向我澄清主线 DHT 规范中的声明吗? Upon inserting the first node into its routing table and when starting up th
我正在尝试使用 USB 小工具驱动程序使嵌入式设备作为 MTP 设备工作。 我知道 Android 从大容量存储设备切换到 MTP 设备已经有一段时间了,并且找到了 source code for M
我是一名优秀的程序员,十分优秀!