std::function 对象本身是线程安全的吗?如果不是,我可以通过什么方式使其线程安全?
Is the std::function object itself thread safe? If no, what ways can I make it thread safe?
我有一个许多线程访问的 std::function
对象。线程可以改变它指向的函数(通过它的拷贝构造函数)并且可以调用它指向的函数。
所以,我的问题是,std::function
对象 本身 线程在哪些方面是安全的?我说的不是它指向to/calls的函数,我说的是std::function对象本身。
令人惊讶的是,互联网上只有少数站点在谈论这个,而且所有这些(我遇到的)都在谈论它指向、[=57 的功能=]不是对象本身.
这些是我阅读过的主要网站:
Does std::function lock a mutex when calling an internal mutable lambda?
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4348.html
如果你读过它们,你会发现其中 none 谈到了 std::function 对象本身的安全性。
根据 this 页面上的第二个答案,STL 库在这些情况下是线程安全的:
可以同时读取同一个对象
同时read/writes不同对象即可
基于此,当我设置 std::function
对象指向的函数时,对于此用例,std::function
对象不是线程安全的。但我问的是以防万一,因为根据 this 问题的答案,它有某种内部互斥体。
那么,有什么方法可以让它成为线程安全的呢?一种选择是使用互斥体,但由于下面演示的示例,这不会完全起作用:
假设我有一个 std::function
对象 func
和 std::mutex m
来保护函数。我锁定 m 并调用函数(以保护其他线程在调用它指向的函数时设置 func),并在函数退出时解锁 m。可以说这个函数调用将花费很长时间。这样,当一个线程想要设置 func 时,它会尝试锁定互斥锁,但会阻塞直到后一个函数调用退出。在这种情况下我能做什么?
我想过使用一个指向 std::function 对象的指针。这样,我将使用互斥锁来保护这个 指针 并且当我进行函数调用时,我锁定互斥锁只是为了从指针中检索函数对象。
函数对象与所有其他对象一样。只是数据,std::function.
中没有内置互斥锁
如果你想用互斥锁保护函数,你自己需要创建一个互斥锁并在与函数交互时使用(将它指向其他东西或调用它)。
#include <functional>
#include <mutex>
#include <iostream>
int main() {
std::mutex functionMutex;
std::function<void()> f = [&functionMutex] {
std::cout << "hello\n" << std::endl;
};
{ // Imagine a new thread
// Procect when calling
auto s = std::scoped_lock{functionMutex};
f();
}
{ // You could wrap it in another function
auto call = [&f, &functionMutex] {
auto s = std::scoped_lock{functionMutex};
f();
};
// Using this pointer would be safe
call();
}
{ // Imagine another thread
auto s = std::scoped_lock{functionMutex};
f = [] {}; // Changing the function "pointer"
}
}
您可以通过赋值或交换来更改std::function
。很明显,您需要保护对它的访问,就像对您分配给的任何其他非原子对象一样。您通常不会通过复制构造函数更改对象,因为复制构造函数会创建一个新对象。
为了保护对 std::function
对象的访问,您不需要指针。
std::function<void()> fun, funCopy, otherFun;
std::mutex mutex;
// thread 1
{
auto s = std::scoped_lock{mutex};
funCopy = fun;
}
funCopy();
// thread 2
{
auto s = std::scoped_lock{mutex};
fun = otherFun;
}
我有一个许多线程访问的 std::function
对象。线程可以改变它指向的函数(通过它的拷贝构造函数)并且可以调用它指向的函数。
所以,我的问题是,std::function
对象 本身 线程在哪些方面是安全的?我说的不是它指向to/calls的函数,我说的是std::function对象本身。
令人惊讶的是,互联网上只有少数站点在谈论这个,而且所有这些(我遇到的)都在谈论它指向、[=57 的功能=]不是对象本身.
这些是我阅读过的主要网站:
Does std::function lock a mutex when calling an internal mutable lambda?
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4348.html
如果你读过它们,你会发现其中 none 谈到了 std::function 对象本身的安全性。
根据 this 页面上的第二个答案,STL 库在这些情况下是线程安全的:
可以同时读取同一个对象
同时read/writes不同对象即可
基于此,当我设置 std::function
对象指向的函数时,对于此用例,std::function
对象不是线程安全的。但我问的是以防万一,因为根据 this 问题的答案,它有某种内部互斥体。
那么,有什么方法可以让它成为线程安全的呢?一种选择是使用互斥体,但由于下面演示的示例,这不会完全起作用:
假设我有一个 std::function
对象 func
和 std::mutex m
来保护函数。我锁定 m 并调用函数(以保护其他线程在调用它指向的函数时设置 func),并在函数退出时解锁 m。可以说这个函数调用将花费很长时间。这样,当一个线程想要设置 func 时,它会尝试锁定互斥锁,但会阻塞直到后一个函数调用退出。在这种情况下我能做什么?
我想过使用一个指向 std::function 对象的指针。这样,我将使用互斥锁来保护这个 指针 并且当我进行函数调用时,我锁定互斥锁只是为了从指针中检索函数对象。
函数对象与所有其他对象一样。只是数据,std::function.
中没有内置互斥锁如果你想用互斥锁保护函数,你自己需要创建一个互斥锁并在与函数交互时使用(将它指向其他东西或调用它)。
#include <functional>
#include <mutex>
#include <iostream>
int main() {
std::mutex functionMutex;
std::function<void()> f = [&functionMutex] {
std::cout << "hello\n" << std::endl;
};
{ // Imagine a new thread
// Procect when calling
auto s = std::scoped_lock{functionMutex};
f();
}
{ // You could wrap it in another function
auto call = [&f, &functionMutex] {
auto s = std::scoped_lock{functionMutex};
f();
};
// Using this pointer would be safe
call();
}
{ // Imagine another thread
auto s = std::scoped_lock{functionMutex};
f = [] {}; // Changing the function "pointer"
}
}
您可以通过赋值或交换来更改std::function
。很明显,您需要保护对它的访问,就像对您分配给的任何其他非原子对象一样。您通常不会通过复制构造函数更改对象,因为复制构造函数会创建一个新对象。
为了保护对 std::function
对象的访问,您不需要指针。
std::function<void()> fun, funCopy, otherFun;
std::mutex mutex;
// thread 1
{
auto s = std::scoped_lock{mutex};
funCopy = fun;
}
funCopy();
// thread 2
{
auto s = std::scoped_lock{mutex};
fun = otherFun;
}