- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
这是一个为什么这个代码不能工作的问题。我想知道如何修复命名空间 dj 中的代码,而不是演示程序中的代码。在进一步阅读之前,您可能需要运行该程序。
当我通过 std::thread
传递 rvalue std::string
时,字符串到达并行函数时为空。也许原始值已被 std::moved,但最终位于错误的位置。但我认为问题可能出在函数 timer
上。我认为字符串是通过引用捕获的,当右值消失时,引用无效。
// In the demo program, the string is the one element of `...args`.
template<typename F, typename... Args>
void timer(double seconds, F& f, Args&&... args) {
auto th = std::thread(
[&, seconds] { delayed(seconds, f, std::forward<Args>(args)...); });
th.detach();
}
我不知道如何为 lambda 捕获数据。符号让我害怕,但我无法解决它。我曾多次尝试使用 bind
或 function
代替 lambda。没有快乐。
...
演示程序... 主线程启动一个暂停给定秒数的进程。然后新线程打印一个字符串并发出哔哔声,直到主线程将原子 bool 值设置为真。要显示它不起作用,请将全局 bool demo_the_problem
设置为 true。字符串到达报警函数时为空。
#include <thread>
#include <chrono>
#include <iostream>
static bool demo_the_problem = false;
namespace dj {
inline void std_sleep(long double seconds) noexcept
{
using duration_t = std::chrono::duration<long long, std::nano>;
const auto duration = duration_t(static_cast<long long> (seconds * 1e9));
std::this_thread::sleep_for(duration);
}
// Runs a command f after delaying an amount of time
template<typename F, typename... Args>
auto delayed(double seconds, F& f, Args&&... args) {
std_sleep(seconds);
return f(std::forward<Args>(args)...);
}
// Runs a function after a given delay. Returns nothing.
template<typename F, typename... Args>
void timer(double seconds, F& f, Args&&... args) {
auto th = std::thread( // XXX This appears to be where I lose ring_tone. XXX
[&, seconds] { delayed(seconds, f, std::forward<Args>(args)...); });
th.detach();
}
}
using namespace dj;
int main() {
std::atomic<bool> off_button(false);
// Test dj::timer, which invokes a void function after a given
// period of time. In this case, the function is "alarm_clock".
auto alarm_clock = [&off_button](const std::string ring_tone) {
char bel = 7;
std::cout << ring_tone << '\n';
while (!off_button) {
std_sleep(0.5);
std::cout << bel;
}
off_button = false;
};
auto ring = std::string("BRINNNNGGG!");
if (demo_the_problem)
timer(4.0, alarm_clock, std::string("BRINNNNGGG!")); // Not OK - ring arrives as empty string
else {
timer(4.0, alarm_clock, ring); // Ring tone arrives intact.
}
// Mess around for a while
for (int i = 0; i < 12; ++i) {
if (i == 7) {
off_button = true; // Hit the button to turn off the alarm
}
std::cout << "TICK ";
std_sleep(0.5);
std::cout << "tock ";
std_sleep(0.5);
}
// and wait for the button to pop back up.
while(off_button) std::this_thread::yield();
std::cout << "Yawn." << std::endl;
return 0;
}
最佳答案
template<typename F, typename... Args>
void timer(double seconds, F& f, Args&&... args) {
auto th = std::thread(
[&, seconds] { delayed(seconds, f, std::forward<Args>(args)...); });
th.detach();
}
这会导致未定义的行为,因为引用捕获的数据销毁没有相对于线程中的代码排序。
永远不要在生命周期(或其拷贝)超过当前作用域的 lambda 上使用 &
。期间。
你的detach
也是代码味道;没有实用的方法来确定线程是否在 main
结束之前完成,并且比 main 还长的线程具有未指定的行为。这是 C++,您有责任清理您的资源使用情况。找到解决方案。我暂时忽略它。
template<typename F, typename... Args>
void timer(double seconds, F&& f, Args&&... args) {
auto th = std::thread(
[seconds,
f=std::forward<F>(f),
tup=std::make_tuple(std::forward<Args>(args)...)
]
{
// TODO: delayed(seconds, f, std::forward<Args>(args)...);
}
);
th.detach();
}
现在我们只需要编写 //TODO
行。
在c++17 ` 这很简单。
template<typename F, typename... Args>
void timer(double seconds, F&& f, Args&&... args) {
auto th = std::thread(
[seconds,
f=std::forward<F>(f),
tup=std::make_tuple(std::forward<Args>(args)...)
]() mutable
{
std::apply(
[&](auto&&...args){
delayed(seconds, f, decltype(args)(args)...);
},
std::move(tup)
);
}
);
th.detach();
}
请注意,此结果将所有内容都复制到线程中。如果您真的非常想传递一个左值引用,请使用 std::ref
,它最适合您。
在c++14或 c++11最好的解决方案是编写自己的 notstd::apply
。有很多人写过这个,包括myself here .
注意我在 lambda 中使用了 [&]
; lambda 不会超过当前范围(事实上它不会超过当前行)。那是您唯一应该使用 [&]
的情况。
关于c++ - 通过 std::thread 传递右值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49387752/
我正在开发一个小型图书馆,我需要做的一件事是让访问者访问一些数据并返回结果。 在一些较旧的 C++ 代码中,访问者需要声明一个 typedef return_type .例如,boost::stati
我正在尝试使用std:map类型的键和值制作std::any Visual Studio 2017 std::map m("lastname", "Ivanov"); std::cout (m["la
我已经在 C++ 的 map 中声明了一个集合为 std::map> .如何循环访问或打印设定值? 最佳答案 如果你知道如何迭代 std::map或 std::set单独地,您应该可以毫无问题地组合迭
如何循环? 我已经试过了: //----- code std::vector >::iterator it; for ( it = users.begin(); it != users.end();
我有两个用例。 A.我想同步访问两个线程的队列。 B.我想同步两个线程对队列的访问并使用条件变量,因为其中一个线程将等待另一个线程将内容存储到队列中。 对于用例 A,我看到了使用 std::lock_
我正在查看这两种类型特征的文档,但不确定有什么区别。我不是语言律师,但据我所知,它们都适用于“memcpy-able”类型。 它们可以互换使用吗? 最佳答案 不,这些术语不能互换使用。这两个术语都表示
我有以下测试代码,其中有一个参数 fS,它是 ofstream 的容器: #include #include #include #include int
这是这个问题的延续 c++ function ptr in unorderer_map, compile time error 我试图使用 std::function 而不是函数指针,并且只有当函数是
std::unordered_map str_bool_map = { {"a", true}, {"b", false}, {"c", true} }; 我们可以在此映射上使
我有以下对象 std::vector> vectorList; 然后我添加到这个使用 std::vector vec_tmp; vec_tmp.push_back(strDRG); vec_tmp.p
为什么 std::initializer_list不支持std::get<> , std::tuple_size和 std::tuple_element ?在constexpr中用得很多现在的表达式,
我有一个像这样定义的变量 auto drum = std::make_tuple ( std::make_tuple ( 0.3f , Ex
假设我有一个私有(private)std::map在我的类(class)里std::map 。我怎样才能将其转换为std::map返回给用户?我想要下面的原型(prototype) const std
假设我有一个私有(private)std::map在我的类(class)里std::map 。我怎样才能将其转换为std::map返回给用户?我想要下面的原型(prototype) const std
问题 我正在尝试将 lambda 闭包传递给 std::thread,它使用任意封闭参数调用任意封闭函数。 template std::thread timed_thread(Function&& f
我想创建一个模板类,可以容纳容器和容器的任意组合。例如,std::vector或 std::map ,例如。 我尝试了很多组合,但我必须承认模板的复杂性让我不知所措。我编译的关闭是这样的: templ
我有一个 std::vector>我将其分配给相同类型的第二个 vector 。 我收到这个编译器错误: /opt/gcc-8.2.0/include/c++/8.2.0/bits/stl_algob
有时候,我们有一个工厂可以生成一个 std::unique_ptr vector ,后来我们想在类/线程/你命名的之间共享这些指针。因此,最好改用 std::shared_ptr 。当然有一种方法可以
这个问题在这里已经有了答案: Sorting a vector of custom objects (14 个答案) 关闭 6 年前。 我创建了一个 vector vector ,我想根据我定义的参
我有三个类(class)成员: public: std::vector > getObjects(); std::vector > getObjects() const; privat
我是一名优秀的程序员,十分优秀!