如何修复此代码中的“在没有活动异常的情况下终止调用”错误?

How to fix "terminate called without an active exception" error in this code?

提问人:Atacan 提问时间:5/27/2023 更新时间:5/27/2023 访问量:147

问:

首先,我是一名学生,所以代码可能不是一个高效或写得很好的代码。对不起。但是,如果它不打扰您,我可以使用一些帮助。

以下是我在主程序中使用的主程序和musical_chairs函数。

void musical_chairs(IntQueueHW6 &my_queue, unsigned int idx,unsigned int remaining_player_num, vector<int> &players)
{

    this_thread::sleep_until(chrono::system_clock::now() + chrono::seconds(2));
    mtx.lock();
    if(!(my_queue.isFull()))
    {
        my_queue.enqueue(idx);// my_queue is a queue with size of total_player_num-1
        cout << "Player " << idx << " captured a chair at ";
        current_time();
        cout << "." << endl;
    }
    else
    //**************** I believe this block causing the error *******************
        not_capture(idx);
        for(int k = 0; k < remaining_player_num; k++)
        {
            if(players[k] == idx)
            {
                players.erase(players.begin()+k);
                break;
            }
        }
    }
    mtx.unlock();
//*************** I believe this block causing the error **********************
}

int main()
{
    unsigned int total_player_num, total_round_num, remaining_player_num;
    cout << "Welcome to Musical Chairs game!" << endl << "Enter the number of players in the game: " << endl;
    cin >> total_player_num;
    remaining_player_num = total_player_num;
    total_round_num = total_player_num - 1;
    cout << "Game Start!" << endl << endl;

    vector<int> players(total_player_num); // creating a vector consists of players IDs
    for(int i=0; i < total_player_num; i++)
    {
        players[i] = i;
    }


    while(remaining_player_num != 1) // until only one player left in te game
    {
        IntQueueHW6 my_queue(total_round_num); // creating a queue with size total_round_num for chair slots
        vector<thread> threads(total_player_num); // create a thread vector for all players

        cout << "Time is now ";
        current_time();
        cout << endl;
        int players_length = players.size();

        for(int i = 0; i < players_length; i++)
        {
            int idx = players[i];
            threads[idx] = thread(&musical_chairs, ref(my_queue), idx, remaining_player_num, ref(players));
        }
        
        for(int i = 0; i < players_length; i++) //joining to threads
        {
            int idx = players[i];
            if(threads[idx].joinable())
            {
                threads[idx].join();
            }
        }
         
        display_remaining_players(players); // changing variables accordingly
        remaining_player_num --;
        total_round_num -- ;
        my_queue.clear();
    }

    unsigned int winner_id = players[0];
    winner_func(winner_id); // this function displays the winner

    return 0;
}

我编写了一个程序,使用多线程模拟“音乐椅”游戏。 当我运行主程序时,我收到“在没有活动异常的情况下终止调用”错误。由于我在互联网上的研究很少,这可能是因为线程超出了范围,但如果是这样,我不知道如何解决它。谁能解释一下如何解决?如果错误是由不同的事情发生的,您能解释一下吗,您能帮我修复此代码吗?提前致谢。

C++ 多线程 向量 终止

评论

1赞 Jerry Coffin 5/27/2023
现在,看起来您的代码甚至不会编译(看起来它在第 13 行之后缺少一个左大括号)。请把一个我们可以构建的最小示例放在一起来演示问题,然后复制并粘贴它(完全按原样)。else
0赞 PaulMcKenzie 5/27/2023
my_queue.clear();-- 奇怪的是,你在循环的末尾有这个,when 是一个局部变量,每次循环迭代时都会被销毁。whilemy_queue

答:

0赞 RandomBits 5/27/2023 #1

之所以调用,是因为线程在未联接的情况下终止。std::terminate

函数中丢失的线程将自身从玩家向量中移除,但与此同时,线程继续执行,在调用 .这里缺乏同步将导致它以随机方式失败,具体取决于线程调度的变幻莫测。musical_chairsmainjoin

鉴于代码结构,这将需要重新考虑才能修复。以下是我能想到的最简单的实现。它使用而不是哪个更有效率。std::atomicstd::mutex

一些简短的说明:

  • 我为玩家选择了 a 而不是 a,因为玩家 ID 是唯一的,从集合中删除元素比从向量中删除元素要容易得多,效率也高得多。std::setstd::vector
  • 为了让游戏更公平,我选择线程作为每一轮的输家——否则,最后一个线程输得太频繁了。middle
  • 线程创建的 lambda 捕获是微妙的。必须按值捕获,以便每个线程都有自己的玩家 ID,但需要通过引用捕获 、 和 ,因为它们都是跨线程共享的。pidqueuechairsloser

示例代码

#include <chrono>
#include <iostream>
#include <mutex>
#include <queue>
#include <set>
#include <thread>
#include <vector>

using std::cin, std::cout, std::endl;
using namespace std::chrono_literals;

using PlayerId = int;
using Queue = std::queue<PlayerId>;
using Players = std::set<PlayerId>;

int main(int argc, const char *argv[]) {
    int initial_number_players{};
    cin >> initial_number_players;

    Players players;
    for (auto i = 0; i < initial_number_players; ++i)
        players.insert(i);

    while (players.size() > 1) {
        Queue queue;
        std::vector<std::thread> threads;

        std::atomic<int> chairs{}, loser{};
        for (auto pid : players) {
            threads.emplace_back([&,pid]() {
                std::this_thread::sleep_for(250ms);
                auto cid = chairs.fetch_add(1);
                if (cid == players.size() / 2)
                    loser = pid;
            });
        }
        for (auto& th : threads)
            if (th.joinable())
                th.join();

        cout << "Player " << loser << " did not capture a chair" << endl;
        players.erase(loser);
    }

    cout << "Player " << *players.begin() << " won" << endl;

    return 0;
}

输出

Player 8 did not capture a chair
Player 0 did not capture a chair
Player 1 did not capture a chair
Player 2 did not capture a chair
Player 6 did not capture a chair
Player 3 did not capture a chair
Player 5 did not capture a chair
Player 4 did not capture a chair
Player 9 did not capture a chair
Player 7 won