Ошибка BOOST_ASSERT в boost :: fiber в сборке Visual Studio "Debug" - PullRequest
0 голосов
/ 21 июня 2020

У меня проблема с boost :: fiber. Мой код основан на примере boost :: fiber "work_stealing. cpp". Немного украсила. Теперь он может работать в Windows Subsystem Linux Ubuntu как для отладки, так и для сборки выпуска. Фактически, до прошлой ночи он может работать на Windows сборке Visual Studio ... Но сегодня я пытаюсь запустить какой-то тест, ошибка BOOST ASSERT возникла при сборке Debug. Сборка Release может работать ...

Я не знаю почему ... так, кто-нибудь знает что-нибудь об этом? Почему только на Windows Debug build? Что я сделал не так?

Я использую cmake как инструмент сборки, Visual Studio 2019 Community Edition как инструмент разработки. Я также тестирую WSL Ubuntu 20.04 и macOS 10.15.x (не могу вспомнить ...).

Спасибо.

-Quan

Сбой, возникший ниже код повышения:

// <boost>/lib/fiber/src/scheduler.cpp
...
void
scheduler::detach_worker_context( context * ctx) noexcept {
    BOOST_ASSERT( nullptr != ctx);
    BOOST_ASSERT( ! ctx->ready_is_linked() );
#if ! defined(BOOST_FIBERS_NO_ATOMICS)
    BOOST_ASSERT( ! ctx->remote_ready_is_linked() );
#endif
    BOOST_ASSERT( ! ctx->sleep_is_linked() );
    BOOST_ASSERT( ! ctx->terminated_is_linked() );
    BOOST_ASSERT( ! ctx->wait_is_linked() ); // <-- [THE ERROR RAISED FROM HERE!]
    BOOST_ASSERT( ctx->worker_is_linked() );
    BOOST_ASSERT( ! ctx->is_context( type::pinned_context) );
    ctx->worker_unlink();
    BOOST_ASSERT( ! ctx->worker_is_linked() );
    ctx->scheduler_ = nullptr;
    // a detached context must not belong to any queue
}
...

И мой код похож на ниже (я удалил некоторые не связанные части ...):

//coroutine.h
class CoroutineManager {
  ...

  typedef std::unique_lock<std::mutex> lock_type;
  typedef boost::fibers::algo::work_stealing scheduler_algorithm;
  typedef boost::fibers::default_stack stack_type;
  
  ...
  void wait() {
    lock_type shutdown_lock(shutdown_mutex);
    shutdown_condition.wait(shutdown_lock, [this]() { return 1 == this->shutdown_flag; });
    BOOST_ASSERT(1 == this->shutdown_flag);
  }

  void shutdown(bool wait = true) {
    lock_type shutdown_lock(shutdown_mutex);

    this->shutdown_flag = 1;

    shutdown_lock.unlock();

    this->shutdown_condition.notify_all();

    if (wait) {
      for (std::thread& t : threads) {
        if (t.joinable()) {
          t.join();
        }
      }
    }
  }
  
  ...

  template <class TaskType>
  void submit(const TaskType& task) {
    boost::fibers::fiber(boost::fibers::launch::dispatch, std::allocator_arg, stack_type(this->stack_size), task).detach();
  }
  
  ...
  
  void init() {
    if (verbose) spdlog::info("INIT THREAD({0}) STARTED.", std::this_thread::get_id());

    for (int i = 0; i < (this->thread_count - 1); ++i) {
      threads.push_back(std::thread(&CoroutineManager::thread, this));
    }

    boost::fibers::use_scheduling_algorithm<scheduler_algorithm>(this->thread_count);

    this->start_barrier.wait();
  }

  void dispose() {
    if (verbose) spdlog::info("INIT THREAD({0}) DISPOSED.", std::this_thread::get_id());
  }

  void thread() {
    if(verbose) spdlog::info("WORKER THREAD({0}) STARTED.", std::this_thread::get_id());

    boost::fibers::use_scheduling_algorithm<scheduler_algorithm>(this->thread_count);

    this->start_barrier.wait();

    this->wait();

    if (verbose) spdlog::info("WORKER THREAD({0}) DISPOSED.", std::this_thread::get_id());
  }

  ...
};

- - - - - - - - - - - - - - - - - - - - - - -

// coroutine_test.cpp
...

int main(int argc, char* argv[]) {
  init_file_logger("coroutine_test.log");
  time_tracker tracker("[coroutine_test.main]");

  typedef std::thread::id tid_t;
  typedef boost::fibers::fiber::id fid_t;
  typedef boost::fibers::buffered_channel<std::tuple<tid_t, fid_t, int>> channel_t;

  CoroutineManager manager(std::thread::hardware_concurrency(), 1024 * 1024 * 8, true);

  const int N = 1;

  channel_t chan { 8 };

  boost::fibers::barrier done_flag(2);

  manager.submit([&chan, &done_flag]() {
    std::tuple<tid_t, fid_t, int> p;

    while( boost::fibers::channel_op_status::success == chan.pop_wait_for(p, std::chrono::milliseconds(100))) {
      spdlog::info("[thead({0}) : fiber({1}) from {2}]", std::get<0>(p), std::get<1>(p), std::get<2>(p));
    }

    done_flag.wait();
  });

  for (int i = 0; i < N; ++i) {
    manager.submit([&chan, i]() {
      for (int j = 0; j < 1000; ++j) {
        chan.push(std::move(std::make_tuple(std::this_thread::get_id(), boost::this_fiber::get_id(), i)));
        boost::this_fiber::yield();
      }
    });
  }

  done_flag.wait();

  spdlog::info("-START TO SHUTDOWN-");

  manager.shutdown();

  spdlog::info("-END-");

  return 0;
}

[ОБНОВЛЕНИЕ] Добавить снимок чтобы объяснить мою ситуацию более ясно ...

1 Ответ

0 голосов
/ 23 июня 2020

Думаю, я обнаружил, как это произошло (хотя и не root причину):

Неудачное утверждение произошло в буферизованном канале с парой push / pop_wait_for. Если вы изменили использование пары try_push / pop, исключение исчезнет.

Я думаю, что это в pop_wait_for, но поскольку информация о стеке очень тусклая, я не могу понять это. Я тоже не эксперт по бусту. Надеюсь, кто-то еще сможет разобраться.

Итак, мой код сейчас выглядит примерно так:

  manager.submit([&chan, &done_flag]() {
    std::tuple<tid_t, fid_t, int> p;

    for (;;) {
      boost::fibers::channel_op_status status = chan.pop(p);
      if (boost::fibers::channel_op_status::success == status) {
        spdlog::info("[thead({0}) : fiber({1}) from {2}]", std::get<0>(p), std::get<1>(p), std::get<2>(p));
      } else if (boost::fibers::channel_op_status::closed == status) {
        spdlog::info("[ off loop ]");
        break;
      }

      boost::this_fiber::yield();
    }
  });

  for (int i = 0; i < N; ++i) {
    manager.submit([&chan, i]() {
      for (int j = 0; j < 1000; ++j) {
        boost::fibers::channel_op_status status = chan.try_push(std::make_tuple(std::this_thread::get_id(), boost::this_fiber::get_id(), i));
        spdlog::warn("[ worker ] status : {0}", (int)status);
      }
    });
  }

И это было примерно так:

  manager.submit([&chan, &done_flag]() {
    std::tuple<tid_t, fid_t, int> p;

    while( boost::fibers::channel_op_status::success == chan.pop_wait_for(p, std::chrono::milliseconds(100))) {
      spdlog::info("[thead({0}) : fiber({1}) from {2}]", std::get<0>(p), std::get<1>(p), std::get<2>(p));
    }
  });

  for (int i = 0; i < N; ++i) {
    manager.submit([&chan, i]() {
      for (int j = 0; j < 1000; ++j) {
        chan.push(std::make_tuple(std::this_thread::get_id(), boost::this_fiber::get_id(), i));
      }
    });
  }

Надеюсь, это поможет другие, попавшие в такую ​​же ситуацию.

...