请考虑这段代码:
#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
两者的生命周期myInt
和 firstime
将在 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/