当前位置: 首页 > 知识库问答 >
问题:

使用void*将对象正确传递给pthread_create()

吴建中
2023-03-14

我一直在按照创建 POSIX 线程的说明进行操作,并密切关注他们的示例 Pthread 创建和终止。

根据他们的示例,他们将一个整数值传递给pthread_create(),这将导致类似于以下内容的调用:

pthread_create(&thread, NULL, do_something, (long*)testVal);

我要运行的代码的草图是:

#include <iostream>
#include <pthread.h>
using namespace std;

// Simple example class.
class Range {
    public:
        int start;
        int end;
        Range(int start_bound, int end_bound) {
            start = start_bound;
            end = end_bound;
        }
        void print() {
            cout << "\n(" << start << ", " << end << ')';
        }
};

void* do_something(void* testVal) {
    std::cout << "Value of thread: " << (long)testVal << '\n';
    pthread_exit(NULL);
}

int main() {
    pthread_t thread;
    Range range = Range(1, 2); // What I really want to pass
    long testVal = 42;         // Let's test

    pthread_create(&thread, NULL, do_something, (void*)testVal);
    pthread_exit(NULL);
}

这是在一个作业的上下文中,老师希望我们在Linux中使用gcc,所以我使用Windows子系统来Linux这些编译参数:

gcc program.cpp -o program -lstdc++ -lpthread

运行上述程序将输出“线程值:42”。

我的 C 指针体验已经过去了几年,但只是为了好玩,让我们将数据类型从 long 更改为 int。这会将语句更改为 int testVal = 42标准:::cout

错误:从“void*”强制转换为“int”会丢失精度(int)testVal

警告:从不同大小的整数pthread_create(

使用整数数据类型不是我想要做的,但我包括了这个例子,因为我猜想问题是从这里开始复合的。

问题如何将< code>Range对象传递给< code>pthread_create()?我需要做一些事情,

void* do_something(void* range) {
    (Range)range.print();
...

...但是我遇到了一堆类型错误。研究有关传递此值的其他问题并未带来太多清晰度。回来的主要问题是从类型“范围”到类型“void*”的无效转换。我对将 void 指针传递给值与将 void 指针传递给寻址类型之间的区别还不够精通,无法理解出了什么问题。测试指针引用、取消引用和强制转换的各种组合无济于事。

共有2个答案

尹善
2023-03-14

在开始手头的任务之前,您需要解决几个基本问题,即将Range的实例传递给新线程。

pthread_exit(NULL);

您将在pthread_exit的文档中找到pthread_exit()如何终止调用线程的说明。值得注意的是,在您的程序中,不能保证do_something在调用pthread_exit之前实际执行。pthread_create给你的只是一个模糊的promise,即创建一个新的执行线程,并将很快开始开展业务。不能保证它会在pthread_create返回之前开始运行,也不能保证新线程将在pthread_exit终止之前运行。

所以,让我们假设你通过某种方式将一个指向range对象的指针传递给你的do_something。好吧,当do_something尝试做某事时,实际的range对象已经消失了,你有一个指向已销毁对象的指针,使用它变成了未定义的行为。

在您的main中,

与其修复它,你可以考虑使用std::线程,而不是POSIX线程,它提供了一个更自然的本机C执行线程实现,可以解决大多数这些问题(如果使用正确)。

蒯宏达
2023-03-14
void* do_something(void* range) {
    (Range)range.print();
...

...但是我遇到了一堆打字错误。

这是因为您的 Range 类不能从指针转换为 void。

问题 如何将范围对象传递给pthread_create()?

通过使用间接寻址pthreadcreate接受指向任何类型对象的指针。这就是void*的意思;它可以指向任何类型的对象。传递对象的地址:

Range range = Range(1, 2);
Range* range_ptr = &range;

pthread_create(&thread, nullptr, do_something, range_ptr);
// or shorter
pthread_create(&thread, nullptr, do_something, &range);

您可以将 void* 静态强制转换为原始指针类型,然后可以通过指针间接访问指向的对象:

void* do_something(void* void_ptr) {
    Range* range_ptr = static_cast<Range*>(void_ptr);
    range_ptr->print();

请注意,使用间接寻址会给示例带来一个问题:只要线程使用它,指向的对象必须至少处于活动状态。这在您的示例案例中不起作用,因为该对象是 main 中的自动变量,该示例在启动另一个线程后立即终止。一种解决方案是通过加入来等待另一个线程结束:

// pthread_exit(NULL); <-- replace this 
pthread_join(thread, nullptr);

这个例子质量不高。它使用重新解释技巧来避免向线程传递整数时的间接寻址,但不应将long重新解释为void*>,因为不能保证它们具有相同的大小,而且不在64位Windows中,因此标准不能保证它们的往返转换的有效性。该示例应该使用std::intptr_t

P.S .不要在C中使用< code>NULL。

P. P. S.避免在C中使用pthread。取而代之的是std::线程

 类似资料:
  • 问题内容: 我在php中有对象,每个对象代表一个“项目”以及与之相关的所有信息。 当用户浏览页面时,这些对象应传递给javascript。理想情况下,镜像相同的结构,因此我可以使用Raphael在我的网站上将每个项目及其信息显示为单独的形状。 但是,如何将对象从php转换为javascript? 问题答案: 您可以将PHP对象转换为数组,然后使用JSON函数对其进行编码。之后,从JavaScrip

  • 问题内容: 我正在尝试学习go,并且一开始我想尝试组装一个超级简单的Web服务器来控制iTunes。过去,我已经多次达到这个目的,并认为我可以在这里简单地取消对osascript的调用。 注释掉的“ say 5”命令 确实 起作用。 我收到的回应如下: 我不确定从这里要去哪里,任何方向都将不胜感激。 问题答案: 我明白了 我认为exec.Command(…)如果参数中有空格,则在参数中添加双引号,

  • 问题内容: 这里有角的新手。我试图找出将对象传递给指令时出了什么问题。 这是我的指令: 这是我调用指令的模板: 是一组对象。 当我运行此,日志,而日志罚款的范围,甚至有一个与所有的数据,我找孩子。 我不确定我在这里做错了什么,因为这种确切的方法以前对我有用。 编辑: 我已经用所有必需的代码创建了一个插件:http ://plnkr.co/edit/uJCxrG 如您所见,该作用域在范围中可用,但我

  • 问题内容: 我想知道是否有可能使用jQuery AJAX函数将数组传递给php函数。我有以下作为我的JavaScript 当我尝试执行以下操作时 我在PHP中将其作为“数组”接收。如何正确发送对象,以便PHP函数可以使用它? 问题答案: 从第二个ajax中,您可以根据属性名称访问数据,例如: 是在php中以关联数组转换的js对象

  • 我在示例中看到如何将消息字符串传递给亚马逊 sns sdk 的发布方法。但是,是否有如何将自定义对象作为消息传递的示例?我尝试将“消息结构”设置为“json”,但随后我得到错误。我应该将对象值传递到参数中的哪个位置? 有什么例子吗?

  • 问题内容: 我想将一个对象传递给控制器​​,并在控制器中检索值。我定义如下: HTML代码: Javascript: 但是我无法在控制器中检索值。它越来越空。 问题答案: 尝试以下操作:-您正在传递对象数组,因此您应该执行HTTPPost而不是HttpGet(这将适用于通过查询字符串发送它的原始类型数组,例如int,strgin等列表)(请记住查询字符串的限制)。尝试使用HTTPPost