向线程函数传递参数

std::thread 构造函数中的可调用对象, 或函数传递一个参数很简单。 需要注意的是, 默认参数要拷贝到线程独立内存中, 即使参数是引用的形式, 也可以在新线程中进行访问 。

void f(int i, std::string const& s);
std::thread t(f, 3, "hello");

代码创建了一个调用f(3, "hello")的线程。 注意, 函数f需要一个 std::string 对象作为第二个参数, 但这里使用的是字符串的字面值, 也就是 char const * 类型。 之后, 在线程的上下文中完成字面值向 std::string 对象的转化。 需要特别要注意, 当指向动态变量的指针作为参数传递给线程的情况, 代码如下: 

void f(int i,std::string const& s);
void oops(int some_param)
{
    char buffer[1024]; // 1
    sprintf(buffer, "%i",some_param);
    std::thread t(f,3,buffer); // 2
    t.detach();
}

这种情况下, buffer是一个指针变量, 指向本地变量, 然后本地变量通过buffer传递到新线程中。 并且, 函数有很有可能会在字面值转化成 std::string 对象之前崩溃(oops), 从而导致一些未定义的行为。 并且想要依赖隐式转换将字面值转换为函数期待的 std::string 对象,但因 std::thread 的构造函数会复制提供的变量, 就只复制了没有转换成期望类型的字符串字面值。 

 解决方案就是在传递到 std::thread 构造函数之前就将字面值转化为 std::string 对象: 

void f(int i,std::string const& s);
void not_oops(int some_param)
{
    char buffer[1024];
    sprintf(buffer,"%i",some_param);
    std::thread t(f,3,std::string(buffer)); // 使用std::string, 避免悬垂指针
    t.detach();
}

不过, 也有成功的情况: 复制一个引用。 在线程更新数据结构时, 会成功的传递一个引用: 

void update_data_for_widget(widget_id w,widget_data& data); // 1
void oops_again(widget_id w)
{
    widget_data data;
    std::thread t(update_data_for_widget,w,data); // 2
    display_status();
    t.join();
    process_widget_data(data); // 3
}

虽然update_data_for_widget的第二个参数期待传入一个引用, 但是 std::thread 的构造函数并不知晓; 构造函数无视函数期待的参数类型, 并盲目的拷贝已提供的变量。 当线程调用update_data_for_widget函数时, 传递给函数的参数是data变量内部拷贝的引用, 而非数据本身的引用。 因此, 当线程结束时, 内部拷贝数据将会在数据更新阶段被销毁, process_widget_data将会接收到没有修改的data变量。 可以使用 std::ref 将参数转换成引用的形式, 从而可将线程的调用改为以下形式: 

std::thread t(update_data_for_widget,w,std::ref(data));

 在这之后, update_data_for_widget就会接收到一个data变量的引用, 而非一个data变量拷贝的引用。 

posted @   小熊酱  阅读(58)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示