C++11:使用 std::thread 和 lambda 函数的段错误
C++11: Segfault with std::thread and lambda function
我已经写了一个小应用程序来演示这个问题,它不是很漂亮,但它完成了工作。
#include <functional>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
class A {
public:
A() : thread_(), tasks_(), mutex_(), a_(99999) {}
void Start() {
thread_ = std::thread([this] () { Run(); });
}
private:
using Task = std::function<void()>;
public:
void AddTask(const Task& task) {
std::lock_guard<std::mutex> lock(mutex_);
tasks_.push(task);
}
bool Empty() {
std::lock_guard<std::mutex> lock(mutex_);
const bool empty = tasks_.empty();
return empty;
}
Task GetTask() {
std::lock_guard<std::mutex> lock(mutex_);
const auto& task = tasks_.front();
tasks_.pop();
return task;
}
int GetInt() { return a_; }
void Join() { thread_.join(); }
private:
void Run() {
while (Empty());
(GetTask())();
}
std::thread thread_;
std::queue<Task> tasks_;
std::mutex mutex_;
int a_;
};
template <class Base>
class B : public Base {
public:
using Base::Base;
void Start() {
Base::Start();
std::cout << "A: " << this << std::endl;
Base::AddTask([this] () { std::cout << "T: " << this << std::endl; Do(); });
}
void Do() {
std::cout << "Do: " << this << std::endl;
std::cout << "GetInt: " << Base::GetInt() << std::endl;
}
};
int main() {
B<A> app;
app.Start();
app.Join();
}
clang++ -std=c++11 -lpthread test_a.cpp
A: 0x7ffeb521f4e8
T: 0x21ee540
Do: 0x21ee540
GetInt: 0
注意 'this' 的变化以及 'GetInt' 的值 0。
我真的迷路了...任何帮助将不胜感激,
谢谢。
我将您的复制品缩小为:
#include <functional>
#include <iostream>
#include <queue>
struct foo {
using Task = std::function<void()>;
void Test() {
std::cout << "In Test, this: " << this << std::endl;
AddTask([this] { std::cout << "In task, this: " << this << std::endl; });
}
void AddTask(const Task& task) {
tasks_.push(task);
}
Task GetTask() {
const auto& task = tasks_.front();
tasks_.pop();
return task;
}
std::queue<Task> tasks_;
};
int main() {
foo f;
f.Test();
auto func = f.GetTask();
func();
}
你现在看到问题了吗?问题在于:
const auto& task = tasks_.front();
tasks_.pop();
在这里您获取了一个对象的引用,然后您告诉队列继续并删除该对象。您的参考现在悬而未决,随之而来的是混乱。
您应该将其移出:
Task GetTask() {
auto task = std::move(tasks_.front());
tasks_.pop();
return task;
}
我已经写了一个小应用程序来演示这个问题,它不是很漂亮,但它完成了工作。
#include <functional>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
class A {
public:
A() : thread_(), tasks_(), mutex_(), a_(99999) {}
void Start() {
thread_ = std::thread([this] () { Run(); });
}
private:
using Task = std::function<void()>;
public:
void AddTask(const Task& task) {
std::lock_guard<std::mutex> lock(mutex_);
tasks_.push(task);
}
bool Empty() {
std::lock_guard<std::mutex> lock(mutex_);
const bool empty = tasks_.empty();
return empty;
}
Task GetTask() {
std::lock_guard<std::mutex> lock(mutex_);
const auto& task = tasks_.front();
tasks_.pop();
return task;
}
int GetInt() { return a_; }
void Join() { thread_.join(); }
private:
void Run() {
while (Empty());
(GetTask())();
}
std::thread thread_;
std::queue<Task> tasks_;
std::mutex mutex_;
int a_;
};
template <class Base>
class B : public Base {
public:
using Base::Base;
void Start() {
Base::Start();
std::cout << "A: " << this << std::endl;
Base::AddTask([this] () { std::cout << "T: " << this << std::endl; Do(); });
}
void Do() {
std::cout << "Do: " << this << std::endl;
std::cout << "GetInt: " << Base::GetInt() << std::endl;
}
};
int main() {
B<A> app;
app.Start();
app.Join();
}
clang++ -std=c++11 -lpthread test_a.cpp
A: 0x7ffeb521f4e8
T: 0x21ee540
Do: 0x21ee540
GetInt: 0
注意 'this' 的变化以及 'GetInt' 的值 0。
我真的迷路了...任何帮助将不胜感激,
谢谢。
我将您的复制品缩小为:
#include <functional>
#include <iostream>
#include <queue>
struct foo {
using Task = std::function<void()>;
void Test() {
std::cout << "In Test, this: " << this << std::endl;
AddTask([this] { std::cout << "In task, this: " << this << std::endl; });
}
void AddTask(const Task& task) {
tasks_.push(task);
}
Task GetTask() {
const auto& task = tasks_.front();
tasks_.pop();
return task;
}
std::queue<Task> tasks_;
};
int main() {
foo f;
f.Test();
auto func = f.GetTask();
func();
}
你现在看到问题了吗?问题在于:
const auto& task = tasks_.front();
tasks_.pop();
在这里您获取了一个对象的引用,然后您告诉队列继续并删除该对象。您的参考现在悬而未决,随之而来的是混乱。
您应该将其移出:
Task GetTask() {
auto task = std::move(tasks_.front());
tasks_.pop();
return task;
}