【问题标题】:How to return a double value from pthread in c++?如何从 c++ 中的 pthread 返回一个双精度值?
【发布时间】:2013-03-11 23:49:15
【问题描述】:

阅读此线程后:How to return a value from thread in C 关于如何从 pthread 返回整数值我测试了它是否可以用于双精度,但它没有。有没有办法像原始线程中描述的那样从 pthread 进程返回双精度、长整数或字符串,而不是返回整数 42?

如果是怎么办?

如果我有一个包含 10 个位置的静态数组和 10 个 pthreads 每次修改不同的位置,我会遇到麻烦吗? 一个例子就像“线程 0 只修改数组 [0],线程 1 只修改数组 [1] 等等”。

【问题讨论】:

  • Steve Jessop 的答案是您想要使用的答案。 stackoverflow.com/a/2251472/315052
  • 史蒂夫的回答不是我想要的。首先是因为它仍然返回一个 int,其次是因为它使用 pthread_exit() 来退出一个 pthread,这是一个可怕的、可怕的解决方案,应该避免。我的代码有一个非常独特的版本,它通过将 int 转换为 uintptr_t 来处理整数,但据我所知,没有什么可以从 double 转换为指针。
  • 你确定要走这条路吗?如果您使用的是 64 位系统,那么(幸运的是) double 和 void* 都有 8 个字节,因此您可以获得所有返回的位...如果您坚持这样做,我会发布答案。不过,您可能应该只管理线程之间的数据访问。
  • @Flame_Phoenix:您不能将int 更改为double 吗?你意识到他正在传递一个指向int 的指针,对吧?不将 int 填充到指针的值中。所以只需将指针传递给双精度。无论您需要做什么才能不使用pthread_exit(比如说,让函数完成),都这样做。
  • 忘记 pthreads。使用现代编译器,并使用 C++ 11。(G++ 和 Clang 有很好的支持,一些顶级专有的也有很好的支持。)

标签: c++ concurrency pthreads pthread-join


【解决方案1】:

线程只需为您希望它返回的结果动态分配内存:

void *myThread(void*)
{
   double* result = (double*) malloc(sizeof(double));

   *result = 42.0;

   return result;
}

应该收集该结果的任何内容都会取消引用使用适当强制转换返回的指针(毕竟这是带有void* 的C),然后释放内存:

// calling thread (or whatever will collect the value)
void* thread_result;
int err = pthread_join( thread_handle, &thread_result);

double dbl = *(double*) thread_result;
free(thread_result);

作为替代方案,无论创建什么线程,都可以将指针传递给线程应该将其放在void* 参数中的线程的结果(如果线程需要的不仅仅是那一点信息,则可能作为结构的一部分)。如果您有理由避免动态内存分配,这可能会让您避免动态内存分配,但它可能会使数据的所有权和生命周期管理起来更加复杂。

【讨论】:

  • 我试过你的解决方案,但它没有编译:S

    pi_PThreads_2.cpp: In function 'void* process(void*)': pi_PThreads_2.cpp:41:41: error: invalid从 'void*' 转换为 'double*' [-fpermissive]

  • 尝试将double* 转换为该行中的void*return (void*)result;
  • @Flame_Phoenix:对不起,我的例子是用 C 语言编写的。在 C++ 源文件中,您需要从 malloc():double* result = (double*) malloc(sizeof(double)); 转换返回值。我已经更新了答案。如果分配代码和释放用于返回值的对象的代码都是 C++,您可能应该使用 new/delete 而不是 malloc/free
【解决方案2】:

这些只是将Steve Jessop's C solution 重新表述为 C++。这些玩具示例(注意缺少错误检查)使用模板来明确如何更改代码以使用double 以外的其他类型。例如,如果工作完成后需要返回多个值,则可以将 double 替换为 class 类型。实际上,基类和模板可能会被删除,MyWorkerwork() 方法将由调用者直接调用,而不是通过虚拟方法。

首先,使用pthread

#include <iostream>
#include <pthread.h>

class WorkerBase {
protected: virtual ~WorkerBase () {}
public:    virtual void * work () = 0;
};

template <typename T>
struct Worker : public WorkerBase { T result; };

extern "C" void *invoke_worker (void *arg) {
    return static_cast<WorkerBase *>(arg)->work();
}

struct MyWorker : public Worker<double> {
    void * work () {
        result = 4.2;
        return 0;
    }
};

int main () {
    pthread_t t;
    MyWorker w;
    pthread_create(&t, 0, invoke_worker, &w);
    pthread_join(t, 0);
    std::cout << "result: " << w.result << std::endl;
    return 0;
}

第二,使用C++11 std::thread

#include <iostream>
#include <thread>

class WorkerBase {
protected: virtual ~WorkerBase () {}
public:    virtual void work () = 0;
           static void invoke (WorkerBase *w) { w->work(); }
};

template <typename T>
struct Worker : public WorkerBase { T result; };

class MyWorker : public Worker<double> {
    void work () { result = 4.2; }
};

int main () {
    MyWorker w;
    std::thread t(MyWorker::invoke, &w);
    t.join();
    std::cout << "result: " << w.result << std::endl;
    return 0;
}

您在帖子中还有一个我错过的问题:

如果我有一个包含 10 个位置的静态数组和 10 个 pthreads 每次修改不同的位置,我会遇到麻烦吗?

这是否会给您带来麻烦可能取决于数组元素类型和您的硬件架构。在实践中,对于在机器字边界上对齐的数组元素,我没有发现这在 x86 架构上是个问题。

【讨论】:

  • 感谢您的长篇回答,但是如果我没记错的话,传递结构和对象比在 pthread 中简单地将双精度写入静态数组(一次写入)要重得多完成了它的工作:S
  • @Flame_Phoenix:我修改了 C++11,使其不再传递对象。如果您反对传递的指针,那么唯一的解决方案就是全局变量。
  • @Flame_Phoenix:你甚至没有工作代码,你担心某事是否“重”?线程本身比您将传递指针的任何结构重得多。
  • 我有一个带有静态数组的工作代码,这是一个“不太好”的解决方案。
【解决方案3】:

我不认为这太难了。我不使用 cstdlib 中的 malloc(size_t),而只是新的。 下面的示例将参数作为结构传递给线程,并返回另一个结构。为了显示它可以采用任何变量类型,我还使用了字符串向量...

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

struct thread_data {
    int number;
    vector<string> strings;
    thread_data (){}
    thread_data(int nr) {
        number = nr;
        strings.push_back("aba\n");
    }
};

struct thread_return_data {
    int S;
    vector<string> R;
};

void *Thread (void *threadarg) {
    thread_return_data *R = new thread_return_data;
    thread_data * Q;
    Q = (thread_data *) threadarg;
    cout << Q->number << endl;
    R->S = 16; //random number
    R->R.push_back("14fjnv"); //random string
    R->R.push_back("28jfhn"); //random string
    pthread_exit(R);
    return 0;
}

int main() {
    thread_data A(4444); //initialize with random int
    thread_return_data *B; //is pointer
    pthread_t aThread; //is variable

    pthread_create(&aThread, NULL, Thread, (void *)&A);
    pthread_join(aThread, (void **)&B);

    cout << B->S << endl;
    cout << B->R[0] << endl;
    cout << B->R[1] << endl;
    cout << A.strings[0];
    delete B;

    return 0;
}    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-10
    • 2011-01-16
    • 1970-01-01
    • 1970-01-01
    • 2016-03-31
    • 2010-10-05
    • 1970-01-01
    • 2014-04-30
    相关资源
    最近更新 更多