C++ C++;线程:从主线程触发一个循环

C++ C++;线程:从主线程触发一个循环,c++,multithreading,c++14,C++,Multithreading,C++14,我有4个传感器,我想在4个不同的线程内异步轮询。我有一个计时器,将调用30Hz的函数,我希望这个函数触发线程内的轮询 我曾尝试使用std::async在每次计时器调用时生成4个线程,但创建线程的开销太大。下面是我对std::async所做的操作: 用于(自动和相机:相机\矢量){ 摄像机不同步,后置( std::async(std::launch::async,[camera]()->bool{ 返回摄像头->轮询(); }) ); } 用于(自动和未来:相机异步){ future.get();

我有4个传感器,我想在4个不同的线程内异步轮询。我有一个计时器,将调用30Hz的函数,我希望这个函数触发线程内的轮询

我曾尝试使用
std::async
在每次计时器调用时生成4个线程,但创建线程的开销太大。下面是我对
std::async
所做的操作:

用于(自动和相机:相机\矢量){
摄像机不同步,后置(
std::async(std::launch::async,[camera]()->bool{
返回摄像头->轮询();
})
);
}
用于(自动和未来:相机异步){
future.get();
}

现在我需要在程序开始时生成4个线程,并等待时钟通知它们解锁并运行进程函数。大概是这样的:

用于(自动和相机:相机\矢量)
{
摄影机线程放置回(std::thread([&camera](){
while(true)
{
等待触发器();
摄像头->轮询();
块_触发器();
}
}));
}
无效驱动程序::轮询线程(){
用于(自动线程:摄影机线程(&U){
触发器线程(线程);
}
}
你会怎么做?我的研究让我找到了互斥体和条件变量。例如但我发现的例子是开始一堆线程,然后让它们结束。不要一次触发一个线程中的一个循环

另外,这里我需要的似乎不是一个线程池,因为每个线程作为一个定义的作业,只需要一个触发器。我说得对吗

在我看来,使用互斥体是正确的做法。我应该将它们存储在与线程向量大小相同的第二个向量中吗?我知道我可以在线程内锁定互斥体,但是我可以从主线程解锁互斥体吗?你有什么建议来实现这一点吗

我正在使用C++14


感谢您的帮助。

以下是我对您需求的理解:

  • 你只需要四条线,不多不少
  • 这四个线程彼此独立,这意味着它们不共享数据
  • 每个线程被触发,每33毫秒执行一次作业,在一个33毫秒内,不能执行多次作业
  • 如果在触发器发生时线程仍在处理上一个作业,则允许该线程忽略此触发器
  • 我将按以下方式进行设计:

    #include <thread>
    #include <vector>
    #include <chrono>
    #include <iostream>
    #include <atomic>
    
    using namespace std;
    
    std::atomic_flag lock0 = ATOMIC_FLAG_INIT;
    std::atomic_flag lock1 = ATOMIC_FLAG_INIT;
    std::atomic_flag lock2 = ATOMIC_FLAG_INIT;
    std::atomic_flag lock3 = ATOMIC_FLAG_INIT;
    
    void trigger() {
        while (true) {
            lock0.clear(); // set to false
            lock1.clear(); // set to false
            lock2.clear(); // set to false
            lock3.clear(); // set to false
            std::this_thread::sleep_for(std::chrono::milliseconds(33)); // 33 ms = 1000ms/30
            // from now on, all threads lost the chance to be triggered
            // they have to wait for the next time
            lock0.test_and_set(); // set to true
            lock1.test_and_set(); // set to true
            lock2.test_and_set(); // set to true
            lock3.test_and_set(); // set to true
        }
    }
    
    void f0()
    {
        while (true) {
            while(!lock0.test_and_set()) {
                std::cout << "f0" << std::endl;
            }
        }
    }
    
    void f1()
    {
        while (true) {
            while(!lock1.test_and_set()) {
                std::cout << "f1" << std::endl;
            }
        }
    }
    
    void f2()
    {
        while (true) {
            while(!lock2.test_and_set()) {
                std::cout << "f2" << std::endl;
            }
        }
    }
    
    void f3()
    {
        while (true) {
            while(!lock3.test_and_set()) {
                std::cout << "f3" << std::endl;
            }
        }
    }
    
    int main()
    {
        std::vector<std::thread> v; // use std::async if you want
        std::thread t(trigger);
        v.emplace_back(f0);
        v.emplace_back(f1);
        v.emplace_back(f2);
        v.emplace_back(f3);
        for (auto &ele : v) {
            ele.join();
        }
        t.join();
    
        return 0;
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    使用名称空间std;
    std::atomic_flag lock0=atomic_flag_INIT;
    std::atomic_flag lock1=atomic_flag_INIT;
    std::atomic_flag lock2=atomic_flag_INIT;
    std::atomic_flag lock3=atomic_flag_INIT;
    无效触发器(){
    while(true){
    lock0.clear();//设置为false
    lock1.clear();//设置为false
    lock2.clear();//设置为false
    lock3.clear();//设置为false
    std::this_thread::sleep_for(std::chrono::毫秒(33));//33毫秒=1000ms/30
    //从现在起,所有线程都失去了被触发的机会
    //他们不得不等待下一次
    lock0.test_和_set();//设置为true
    lock1.test_和_set();//设置为true
    lock2.test_和_set();//设置为true
    lock3.test_和_set();//设置为true
    }
    }
    void f0()
    {
    while(true){
    而(!lock0.test_和_set()){
    
    std::那么当计时器触发时,它会产生另外四个新线程吗?在线程内部执行等待难道不是更有意义吗,否则主线程仍然会为发送线程信号而烦恼吗?@Yves理想情况下不会,我希望线程等待触发。看起来你需要的确实是一个线程池。它会ld允许您保持4个线程的活动状态,并在必要时唤醒它们(当您给线程池一个要执行的任务时)。但是对于互斥体和条件变量,这基本上是相同的:)@Fareanor最简单的方法是什么?有什么建议吗?那么我应该有一个互斥体吗?请注意,在诸如
    test\u和\u set
    之类的操作上旋转效率极低,因为它涉及缓存争用。最好在锁解锁之前,在普通加载/读取上旋转。此外,在这个设置中,所有的原子标记都可能在同一个高速缓存行中结束,这会使事情变得更糟。我会考虑将它们对齐到缓存行,例如用<代码>对齐(64)。
    @DanielLangr非常有用的信息。@DanielLangr但是
    std::atomic_flag
    不提供加载或存储操作…有什么建议吗?当然,你看过我发布的链接了吗?他们在那里使用
    std::atomic