协程、std::jthread、MSVC 和崩溃

如何解决协程、std::jthread、MSVC 和崩溃

我的代码在 Archlinux 下使用 GCC 10.2 似乎没有任何问题。 我在几次迭代中使用了 valgrind,但没有检测到任何内存问题。

我制作了一些互斥锁和条件变量帮助器来简化我的代码。 这是我的代码:

#include <atomic>
#include <condition_variable>
#include <coroutine>
#include <deque>
#include <iostream>
#include <optional>
#include <shared_mutex>
#include <string_view>
#include <thread>
#include <utility>
#include <vector>

#define FWD(x) std::forward<decltype(x)>(x)

template <typename... Ts> void display(Ts... ts) {
  static std::mutex m;
  m.lock();
  std::cout << "this_thread: " << std::this_thread::get_id() << ": ";
  ((std::cout << ts << " "),...);
  std::cout << std::endl;
  m.unlock();
}

template <typename T,typename Lock> struct LockedValue {
  LockedValue(T &value,Lock &&lock)
      : m_value{value},m_lock{std::move(lock)} {}
  T &operator*() { return m_value; }
  T *operator->() { return &m_value; }

  void lock() { m_lock.lock(); }
  void unlock() { m_lock.unlock(); }

private:
  T &m_value;
  Lock m_lock;
};

template <typename T> class Mutex {
public:
  template <typename... Args> Mutex(Args &&...args) : m_value{FWD(args)...} {}

  auto lock() { return LockedValue{m_value,std::unique_lock{m_mutex}}; }
  auto lock() const { return LockedValue{m_value,std::shared_lock{m_mutex}}; }

private:
  friend class ConditionVariable;
  T m_value;
  mutable std::shared_mutex m_mutex;
};

class ConditionVariable {
public:
  void notifyOne() { m_cond.notify_one(); }
  void notifyAll() { m_cond.notify_all(); }

  template <typename F,typename Args>
  void wait(F f,const Mutex<Args> &mutexes) {
    auto lock = mutexes.lock();
    m_cond.wait(lock,[&] { return f(*lock); });
  }

  template <typename F,std::stop_token st,st,[&] { return f(*lock); });
  }

private:
  std::condition_variable_any m_cond;
};

struct Awaiter {
public:
  Awaiter() {}

  template <typename... Args>
  Awaiter(std::coroutine_handle<Args...> handle) : m_handle{handle} {}

  Awaiter(const Awaiter &) = delete;
  Awaiter(Awaiter &&a) : m_handle{a.m_handle} { a.m_handle = nullptr; }

  void resume() { m_handle(); }

private:
  std::coroutine_handle<> m_handle = nullptr;
};

class Thread {
  struct Awaitable {
    Thread &thread;
    bool await_ready() { return false; }

    void await_suspend(std::coroutine_handle<> handle) {
      thread.addAwaiter({handle});
    }

    void await_resume() {}
  };

public:
  Thread(std::string name) : m_name{std::move(name)} {
    m_thread = std::jthread([this](std::stop_token st) { run(st); });
  }

  void addAwaiter(Awaiter &&awaiter) {
    m_awaiters.lock()->push_back(std::move(awaiter));
    m_conditionVariable.notifyOne();
  }

  auto id() { return m_thread.get_id(); }

  Awaitable operator co_await() { return {*this}; }

private:
  void run(std::stop_token st) {
    while (!st.stop_requested()) {
      m_conditionVariable.wait(&Thread::hasAwaiters,m_awaiters);

      std::optional<Awaiter> awaiter;
      {
        auto awaiters = m_awaiters.lock();
        if (!awaiters->empty()) {
          awaiter.emplace(std::move(awaiters->front()));
          awaiters->pop_front();
        }
      }

      if (awaiter)
        awaiter->resume();
    }
  }

  static bool hasAwaiters(const std::deque<Awaiter> &awaiters) {
    return !awaiters.empty();
  }

private:
  std::string m_name;
  Mutex<std::deque<Awaiter>> m_awaiters;

  ConditionVariable m_conditionVariable;
  std::jthread m_thread;
};

struct task {
  struct promise_type {
    task get_return_object() { return {}; }
    std::suspend_never initial_suspend() noexcept { return {}; }
    std::suspend_never final_suspend() noexcept { return {}; }
    void return_void() {}
    void unhandled_exception() noexcept {}

    ~promise_type() {}
  };

  ~task() {}
};

std::atomic_int x = 0;

std::atomic_int done = 0;

task f(Thread &thread1,Thread &thread2) {
  co_await thread1;
  ++x;

  co_await thread2;
  ++x;
  ++done;
}

using namespace std::chrono_literals;

static auto N_ITER = 1;
static auto loop = 10'000'000;
int main() {
  std::ios_base::sync_with_stdio(false);
  display("Single task");
  for (int i = 0; i < loop; ++i) {
    Thread thread1{"A"};
    Thread thread2{"B"};
    x = 0;
    done = 0;

    for (int j = 0; j < N_ITER; ++j)
      f(thread1,thread2);

    int j = 0;
    while (done < N_ITER)
      ;

    if (x != N_ITER * 2) {
      std::cout << "error at ith" << i << std::endl;
    }
    if (i % 1'000'000 == 0)
      std::cout << i << std::endl;
  }

  N_ITER *= 500;
  display("Middle of task");
  for (int i = 0; i < loop; ++i) {
    Thread thread1{"A"};
    Thread thread2{"B"};
    x = 0;
    done = 0;

    for (int j = 0; j < N_ITER; ++j)
      f(thread1,thread2);

    int j = 0;
    while (done < N_ITER)
      ;

    if (x != N_ITER * 2) {
      std::cout << "error at ith" << i << std::endl;
    }
    if (i % 1'000'000 == 0)
      std::cout << i << std::endl;
  }

  // Lot of task
  std::cout << "Now lot of task" << std::endl;
  loop /= 1000;
  N_ITER *= 1000;
  for (int i = 0; i < loop; ++i) {
    Thread thread1{"A"};
    Thread thread2{"B"};
    x = 0;
    done = 0;

    for (int j = 0; j < N_ITER; ++j)
      f(thread1,thread2);

    int j = 0;
    while (done < N_ITER)
      ;

    if (x != N_ITER * 2) {
      std::cout << "error at ith" << i << std::endl;
    }
    if (i % 1000 == 0)
      std::cout << i << std::endl;
  }

  return 0;
}

这是代码的想法: 我创建了 2 个线程,我启动了一个协程,我在第一个线程中执行了第一部分,在第二个线程中执行了第二部分。

在主线程中,我等待结束,然后删除线程,然后重新执行。

正如我所说,在 linux gcc 下,我没有任何问题,但是,在 MSVC 上,我遇到了一些奇怪的问题。当我整夜启动测试时,我没有任何崩溃。但是,有时,当我在计算机上执行某些操作时,例如在 microsoft edge 上阅读文档时,“测试代码”会崩溃,有时与“忙时互斥量被破坏”有关。

所以我不知道这是我代码中的错误,还是其他地方的错误(可能是 MSVC)。自然,我认为我的代码有问题,但实际上,我不知道我在哪里做错了...

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res