我正在使用std :: threads实现生产者,该生产者会进行一些长时间的计算,但是所使用的代码并未提供中止方法。但是我需要调用线程在请求中止后立即继续前进。 所以我试图通过调用detach()放弃线程。这个想法是线程完成了计算,但是结果却被丢弃了:
#include <thread>
#include <iostream>
#include <queue>
#include <mutex>
class C
{
public:
void spawn()
{
t1.swap(std::thread(&C::producer, this, 1));
}
void abort()
{
std::lock_guard<std::mutex> lk(mx);
aborted = true;
t1.detach();
}
bool tryGetResult(int &result)
{
std::lock_guard<std::mutex> lk(mx);
if (!q.empty()) {
result = q.front();
q.pop();
return true;
}
else
return false;
}
private:
std::thread t1;
std::mutex mx;
std::queue<int> q;
bool aborted = false;
void producer(int id)
{
int i = 0;
while (true) {
std::lock_guard<std::mutex> lk(mx);
if (aborted) break;
q.push(id * 10 + i);
i++;
}
}
};
int main()
{
{
C c;
c.spawn();
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
c.abort();
}
std::cout << "Done...";
std::cin.get();
}
这种方法似乎奏效,但对我来说却闻起来。 我不明白为什么该线程不会引起访问冲突,因为它在对象被销毁后会尝试访问该对象。
是否有一种方法可以通知线程它已被分离,并且必须退出而不访问任何类成员。
答案 0 :(得分:1)
t1.swap(std::thread(&C::producer, this, 1));
上面的格式不正确,因为声明了std::thread::swap
:
void swap( thread& other ) noexcept;
std::thread(&C::producer, this, 1)
是一个临时值,因此是一个右值。不能将其绑定到swap
的非常量左值引用。
也许您确实想写t1 = std::thread(&C::producer, this, 1);
。
我不明白为什么该线程不会引起访问冲突
在对象生命周期之外访问对象的行为是不确定的。不保证会导致访问冲突。
可以吗
否。
还是有更好的方法来实现这样的东西?
理想的解决方案取决于具体情况。
一个简单的解决方案是使用有状态的可调用对象创建线程,并存储指向共享状态的共享指针。寿命更长的人都可以保持生命。如果经常访问状态,这可能会对性能产生影响。
更简单的解决方案是将静态存储用于共享状态。这没有共享指针可能存在的潜在性能问题,但是全局状态还存在其他问题。
答案 1 :(得分:0)
在销毁C类之后,线程将清楚地访问数据。这是未定义的行为,因此请勿依赖。
如果我对您的理解正确,那么您希望能够在退出程序之前终止线程。这本质上是不安全的,因为您不知道线程在终止时正在访问哪个内存,并且您的程序很可能会处于错误状态。
终止线程的唯一正确方法是关闭线程本身。您已经在中止功能中执行了此操作。这会将aborted
变量设置为true
,这反过来会破坏您的线程循环并退出线程功能。
但是,与其执行分离操作,不如加入它,而应该加入线程。这将使您的主线程等到您的工作线程终止后再继续。在此之后,可以安全删除C。
答案 2 :(得分:0)
如已接受的答案中所建议,shared_ptr可以提供所需的行为。 在中止情况下,shared_ptr的生存时间与最后一个废弃线程的生存时间一样。
#include <thread>
#include <iostream>
#include <queue>
#include <mutex>
#include <memory>
class C
{
public:
~C()
{
std::cout << "Dtor\n";
}
void abort()
{
std::lock_guard<std::mutex> lk(mx);
aborted = true;
}
std::mutex mx;
std::queue<int> q;
bool aborted = false;
static void staticProducer(std::shared_ptr<C> arg, int id)
{
arg->producer(id);
}
void producer(int id)
{
int i = 0;
while (i<300000) {
std::lock_guard<std::mutex> lk(mx);
if (aborted) break;
q.push(id * 10 + i);
i++;
std::cout << "Push\n";
}
}
};
int main()
{
{
std::shared_ptr<C> c = std::make_shared<C>();
std::thread t1 = std::thread(&C::staticProducer, c, 1);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
// scenario 1: abort
c->abort();
t1.detach();
// scenario 2: wait for completion and get result
// t1.join();
// std::cout << c->q.size() << "\n";
}
std::cout << "Done...";
std::cin.get();
}