gpt4 book ai didi

c++ - 在主线程之外的计时器或命令上销毁/替换线程

转载 作者:行者123 更新时间:2023-12-02 10:22:39 25 4
gpt4 key购买 nike

目前我正在为在线游戏开发服务器,并决定将其实现为多线程应用程序。

我有一个实现 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() .

但我还需要实现强制转向结束方法,所以我有 2 种情况的竞争条件:
  • 开始 -> 以 10 秒超时结束正常工作流程(这使得游戏
    线程不可用 10 秒)
  • 强制转弯结束命令 (TURN_END)。

  • 所以我需要以某种方式结束当前的游戏线程并用一个用户线程替换。或者只是用条件变量以某种方式捕获信号,但我已经卡住了 10 秒,据我所知,我不能同时等待两件事(条件变量和 sleep 结束)。

    也许多线程根本不是一个好的解决方案。请在这种情况下分享您的方法。

    谢谢

    最佳答案

    与其说多线程是一种不好的方法,不如说是您的具体实现不正确。

    调用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/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com