如何正确地将参数传递给pthread

时间:2015-10-11 01:38:21

标签: c++ multithreading arguments pthreads void

我试图找到一种方法让我的程序使用windows.h库中的Beep()函数同时产生两声嘟嘟声。我决定使用几个pthreads来做到这一点。但是,我在创建一组可通过的参数时遇到了麻烦。

我对编程很陌生,对于type_casting或void *语法/规则/目的一无所知。我知道它是指向任何类型数据的指针。我想尽可能多地了解多线程和void * s,因为它们似乎非常有用。如果有人可以推荐一些好的文章或教程(考虑到初学者)我会非常感激。

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



 void *tone(void *note)
 {
     double freq;
     freq = double(note);
     Beep(freq, 5000);
 }

 int main()
 {
     double C5 = 523.25;
     double D5 = 587.33;
     double E5 = 659.25;
     double F5 = 698.46;
     double G5 = 783.99;
     double A5 = 880.00;
     double B5 = 987.77;
     double C6 = 1046.50;

     pthread_t tone1;
     pthread_t tone2;

     pthread_create(&tone1, NULL, tone, (void *) C5);

 }

另外,我希望我的代码正确发布。我之前只做了一次。

1 个答案:

答案 0 :(得分:4)

首先,您应该知道pthread库(也就是POSIX线程)是POSIX系统的线程库,这是目前大多数现代操作系统除了 for Windows;但是<windows.h>是一个非常Windows的标题,所以你永远不应该在同一个程序中混合使用它们,除非你是针对模拟或兼容层或类似的开发(例如在Windows上使用Cygwin,或者在Linux上使用Wine)。

无论你使用哪个线程库,答案仍然是一样的。 POSIX的pthread_create()和Windows“CreateThread() / _beginthreadex()都会将void*参数传递给您的线程过程。但是,如果您不想 - 操作系统将其视为不透明的blob并将其传递给未经修改的blob,则您不必实际传递实际指针值。因此,只要您想要传递的数据不大于指针,您就可以将其转换为路径上的指针并将其转发回另一侧。

例如,如果要将整数传递给线程过程:

int theAnswer = 42;
pthread_create(..., &thread_proc, (void *)(intptr_t)theAnswer);
...
void *thread_proc(void *param) {
    int theAnswer = (int)(intptr_t)param;  // Contains 42
    ...
}

您的示例传递double值,该值在64位系统上可能与指针的大小相同,因此您可以使用相同的技巧,例如union;但它肯定会比32位系统上的指针大。

为了将超过指针的数据传递给线程过程,您需要将该数据放在内存中的某个位置,然后传递一个指向该数据的指针。棘手的部分是管理内存,特别是在使用相同的线程过程创建多个线程的情况下。

一个常见的错误是在堆栈上分配数据并在循环中创建多个线程,其循环的参数指向该堆栈数据。但是,所有这些线程都将指向相同的堆栈数据,并且它们最终读取的实际数据将成为具有大量未定义行为的大竞争条件。

管理内存的正确方法是为每个线程动态分配它,然后让新线程负责释放内存。每个线程都有自己的数据副本,没有内存泄漏,并且没有竞争条件。

这是一个无论double是否大于指针(即32位和64位系统)都能工作的示例:

// Allocate dynamic memory for the thread parameter.  If you want to pass more
// than one value, create a struct instead.
double *theAnswer = new double(42.0);
pthread_create(..., &thread_proc, theAnswer);
...
void *thread_proc(void *param) {
    // Order of operations here is important: dereference the value first, then
    // free the memory
    double *theAnswerPtr = (double *)param;
    double theAnswer = *theAnswerPtr;
    delete theAnswerPtr;
    // theAnswer is now 42.0, use it
    ...
}