C++ 线程从线程

标签 c++ multithreading

请考虑这段代码:

#include <stdio>

int myInt = 10;
bool firstTime = true;

void dothings(){ 
    /*repeatedly check for myInt here*/ 
    while(true) {
        if(myInt > 200) { /*send an alert to a socket*/}
    }
}
void launchThread() { 
    if (firsttime) {
        std::thread t2(dothings); 
        t2.detach();
        firsttime = false;
    } else {
    /* update myInt with some value here*/
    }
    return;
}
int main() {

    /* sleep for 4 seconds */
    while(true) {
        std::thread t1(launchThread);
        t1.detach();
    }
} 

我必须调用 launchthread - 没有其他方法可以更新值或启动线程 t2 - 这就是第三方 SDK 的设计方式。

请注意,launchThread 首先退出。 Main 将继续循环。

然而,据我了解,dothings() 将继续运行。

我的问题是 - dothings 在随后从 main 调用 launchThread 之后是否仍然可以访问 myInt 的新更新值?

我无法在谷歌上找到明确的答案 - 但我相信它会 - 但它不是线程安全的并且可能发生数据损坏。但也许这里的专家可以纠正我。谢谢。

最佳答案

关于myInt的生命周期和 firsttime

两者的生命周期myIntfirstime将在 main() 之前开始运行,并在 main() 之后结束返回。都不是launchThread也不doThings管理任何变量的生命周期(t2 除外,它无论如何都是分离的,所以应该无关紧要)。

一个线程是由主线程启动的,还是由任何其他线程启动的,没有任何关系。一个线程一旦启动,特别是当它被分离时,它基本上是独立的:它与程序中运行的其他线程没有关系。

你不能在没有同步的情况下访问共享内存

但是,是的,您会遇到问题。 myInt在多个线程之间共享,因此您必须同步访问它。如果不这样做,您最终会遇到由于同时访问共享内存而导致的未定义行为。最简单的同步方式myInt就是把它变成一个atomic .

我假设只有一个线程在运行 launchThread在每个给定的时间。但是,看看您的示例,情况可能并非如此。如果不是,还需要同步firsttime .

备选方案

但是,您的 myInt看起来很像 Condition Variable .也许你想要 doThings在满足您的条件(myInt > 200)之前被阻止。一个std::condition_variable会帮你的。这将避免 busy wait并为您的处理器节省一些周期。使用 Message Queues 的某种事件系统也可以在这方面帮助您,它甚至可以使您的程序更干净、更易于维护。


下面是一个使用条件变量和原子同步线程的小例子。我尽量保持简单,所以这里仍然有一些改进。我将这些留给您自行决定。

#include <atomic>
#include <condition_variable>
#include <iostream>
#include <thread>

std::mutex cv_m; // This mutex will be used both for myInt and cv.
std::condition_variable cv;
int myInt = 10; // myInt is already protected by the mutex, so there's not need for it to be an atomic.

std::atomic<bool> firstTime{true}; // firstTime does need to be an atomic, because it may be accessed by multiple threads, and is not protected by a mutex.

void dothings(){
    while(true) {
      // std::condition_variable only works with std::unique_lock.
      std::unique_lock<std::mutex> lock(cv_m);

      // This will do the same job of your while(myInt > 200).
      // The difference is that it will only check the condition when
      // it is notified that the value has changed.
      cv.wait(lock, [](){return myInt > 200;});

      // Note that the lock is reaquired after waking up from the wait(), so it is safe to read and modify myInt here.
      std::cout << "Alert! (" << myInt << ")\n";
      myInt -= 40; // I'm making myInt fall out of the range here. Otherwise, we would get multiple alerts after the condition (since it would be now true forever), and it wouldn't be as interesting.
    }
}

void launchThread() { 
    // Both the read and the write to firstTime need to be a single atomic operation.
    // Otherwise, two or more threads could read the value as "true", and assume this is the first time entering this function.
    if (firstTime.exchange(false)) {
      std::thread t2(dothings); 
      t2.detach();
    } else {
      {
        std::lock_guard<std::mutex> lock(cv_m);
        myInt += 50;
      }
      // Value of myInt has changed. Notify all waiting threads.
      cv.notify_all();
    }
    return;
}

int main() {
    for (int i = 0; i < 6; ++i) { // I'm making this a for loop just so I can be sure the program exits
        std::thread t1(launchThread);
        t1.detach();
    }

    // We sleep only to wait for anything to be printed. Your program has an infinite loop on main() already, so you don't have this problem.
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

See it live on Coliru!

关于C++ 线程从线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56262226/

相关文章:

c++ - 初始化文件范围变量时出现段错误

c# - 在另一个线程中安全地访问字典?

java - 如何使用多线程并行运行两个类?

Java线程相当于Python线程守护进程模式

c++ - 关键字 "value"是什么意思?

C++套接字二进制文件

c++ - 非多态类型派生类型的虚拟基础

c++ - 确定多个集合中的唯一值

c - 为什么 write() 终止我的线程?

java - 每个 JVM 实例上开始执行多少线程?