如何将参数传递给Thread对象?

时间:2021-08-08 15:13:33

I'm working with a C++ class-library that provides a Thread base-class where the user has to implement a run() method.

我正在使用一个C ++类库,它提供了一个Thread基类,用户必须在其中实现run()方法。

Is there a recommended way on how to pass parameters to that run() method? Right now I prefer to pass them via the constructor (as pointers).

有关如何将参数传递给run()方法的推荐方法吗?现在我更喜欢通过构造函数传递它们(作为指针)。

7 个解决方案

#1


I'm not sure about C++, but that's how you would do it in Java. You'd have a class that extends Thread (or implements Runnable) and a constructor with the parameters you'd like to pass. Then, when you create the new thread, you have to pass in the arguments, and then start the thread, something like this:

我不确定C ++,但这就是你用Java做的。你有一个扩展Thread(或实现Runnable)的类和一个你想传递参数的构造函数。然后,当您创建新线程时,您必须传入参数,然后启动线程,如下所示:

Thread t = new MyThread(args...);
t.start();

Must be the same in your case.

在你的情况下必须是相同的。

#2


An alternative is to extend this Thread class to accept a functor as only constructor parameter, so that you can bind any call inside it.

另一种方法是将此Thread类扩展为仅接受一个functor作为构造函数参数,以便您可以绑定其中的任何调用。

Then the class using threads wont need to inherit from Thread, but only have one (or more) Thread member. The functor calls any start point you want ( some method of the class with any parameters )

然后使用线程的类不需要从Thread继承,但只有一个(或多个)Thread成员。仿函数调用你想要的任何起始点(带有任何参数的类的某个方法)

#3


Here is a typical pattern:

这是一个典型的模式:

1) Define a data structure that encapsulates all the data your thread needs 2) In the main thread, instantiate a copy of the data structure on the heap using operator new. 3) Fill in the data structure, cast the pointer to void*, pass the void* to the thread procedure by whatever means you are provided by your thread library. 4) When the worker thread gets the void*, it reinterpret_cast's it to the data structure, and then takes ownership of the object. Meaning when the thread is done with the data, the thread deallocates it, as opposed to the main thread deallocating it.

1)定义封装线程所需的所有数据的数据结构2)在主线程中,使用operator new在堆上实例化数据结构的副本。 3)填写数据结构,将指针强制转换为void *,通过线程库提供的任何方式将void *传递给线程过程。 4)当工作线程获得void *时,它将它重新解释为广播到数据结构,然后取得对象的所有权。当线程完成数据时,线程解除分配它,而不是主线程解除分配它。

Here is example code you can compile & test in Windows.

这是您可以在Windows中编译和测试的示例代码。

    #include "stdafx.h"
    #include <windows.h>
    #include <process.h>

    struct ThreadData
    {
        HANDLE isRunning_;
    };

    DWORD WINAPI threadProc(void* v)
    {

    ThreadData* data = reinterpret_cast<ThreadData*>(v);
    if( !data )
        return 0;

    // tell the main thread that we are up & running
    SetEvent(data->isRunning_);

    // do your work here...

    return 1;
}

int main()
{
    // must use heap-based allocation here so that we can transfer ownership
    // of this ThreadData object to the worker thread.  In other words, 
    // the threadProc() function will own & deallocate this resource when it's
    // done with it.
    ThreadData * data = new ThreadData;
    data->isRunning_ = CreateEvent(0, 1, 0, 0);

    // kick off the new thread, passing the thread data
    DWORD id = 0;
    HANDLE thread = CreateThread(0, 0, threadProc, reinterpret_cast<void*>(data), 0, &id);

    // wait for the worker thread to get up & running
    //
    // in real code, you need to check the return value from WFSO and handle it acordingly.  
    // Here I assume the retval is WAIT_OBJECT_0, indicating that the data->isRunning_ event 
    // has become signaled
    WaitForSingleObject(data->isRunning_,INFINITE); 

    // we're done, wait for the thread to die
    WaitForSingleObject(thread, INFINITE);
    CloseHandle(thread);

    return 0;

}

#4


A common problem with thread startup is that the arguments passed exist on only the stack in the calling function. Thread startup is often deferred, such that the calling function returns and it is only some time later the thread actually starts - by which time the arguments are no longer in existence.

线程启动的一个常见问题是传递的参数仅存在于调用函数的堆栈中。线程启动通常是延迟的,这样调用函数就会返回,并且只是一段时间后线程实际启动 - 这时参数不再存在。

One solution to this is to create an event and then start the thread, passing the event as one of the arguments. The starting function then waits on the event, which is signalled by the thread when it has completed startup.

对此的一个解决方案是创建一个事件,然后启动该线程,将事件作为参数之一传递。然后,启动函数等待事件,该事件在完成启动时由线程发出信号。

#5


You can pass the parameters as members of the thread class. The thread which creates the thread can presumably call other methods and/or call member functions before the thread starts. Therefore it can populate whatever members are necessary for it to work. Then when the run method is called, it will have the necessary info to start up.

您可以将参数作为线程类的成员传递。在线程启动之前,创建线程的线程可能会调用其他方法和/或调用成员函数。因此,它可以填充其工作所需的任何成员。然后,当调用run方法时,它将具有启动所需的信息。

I am assuming that you will use a separate object for each thread.

我假设你将为每个线程使用一个单独的对象。

You would normally put all the threads you create into an array, vector etc.

您通常会将您创建的所有线程放入数组,向量等。

#6


It is ok to pass them via constructor. Just be sure that pointers will live longer than the thread.

可以通过构造函数传递它们。请确保指针的活动时间比线程长。

#7


Well, I'd prefer to put the parameters in the Start() method, so you can have a protected constructor, and doesn't have to cascade the parameters through derived class constructor.

好吧,我更喜欢将参数放在Start()方法中,因此您可以拥有受保护的构造函数,而不必通过派生类构造函数级联参数。

I'd prolly let my decleration look something like this:

我会让我的变相看起来像这样:

class Thread
{
public:
   virtual void Start(int parameterCount, void *pars);
protected:
   Thread();
   virtual void run(int parameterCount, void *pars) = 0;
}

Just make sure that your parameters are somehow contracted, e.g. #1 will be int, #2 will be a double etc. etc. :)

只需确保您的参数以某种方式签约,例如#1将是int,#2将是double等等。:)

#1


I'm not sure about C++, but that's how you would do it in Java. You'd have a class that extends Thread (or implements Runnable) and a constructor with the parameters you'd like to pass. Then, when you create the new thread, you have to pass in the arguments, and then start the thread, something like this:

我不确定C ++,但这就是你用Java做的。你有一个扩展Thread(或实现Runnable)的类和一个你想传递参数的构造函数。然后,当您创建新线程时,您必须传入参数,然后启动线程,如下所示:

Thread t = new MyThread(args...);
t.start();

Must be the same in your case.

在你的情况下必须是相同的。

#2


An alternative is to extend this Thread class to accept a functor as only constructor parameter, so that you can bind any call inside it.

另一种方法是将此Thread类扩展为仅接受一个functor作为构造函数参数,以便您可以绑定其中的任何调用。

Then the class using threads wont need to inherit from Thread, but only have one (or more) Thread member. The functor calls any start point you want ( some method of the class with any parameters )

然后使用线程的类不需要从Thread继承,但只有一个(或多个)Thread成员。仿函数调用你想要的任何起始点(带有任何参数的类的某个方法)

#3


Here is a typical pattern:

这是一个典型的模式:

1) Define a data structure that encapsulates all the data your thread needs 2) In the main thread, instantiate a copy of the data structure on the heap using operator new. 3) Fill in the data structure, cast the pointer to void*, pass the void* to the thread procedure by whatever means you are provided by your thread library. 4) When the worker thread gets the void*, it reinterpret_cast's it to the data structure, and then takes ownership of the object. Meaning when the thread is done with the data, the thread deallocates it, as opposed to the main thread deallocating it.

1)定义封装线程所需的所有数据的数据结构2)在主线程中,使用operator new在堆上实例化数据结构的副本。 3)填写数据结构,将指针强制转换为void *,通过线程库提供的任何方式将void *传递给线程过程。 4)当工作线程获得void *时,它将它重新解释为广播到数据结构,然后取得对象的所有权。当线程完成数据时,线程解除分配它,而不是主线程解除分配它。

Here is example code you can compile & test in Windows.

这是您可以在Windows中编译和测试的示例代码。

    #include "stdafx.h"
    #include <windows.h>
    #include <process.h>

    struct ThreadData
    {
        HANDLE isRunning_;
    };

    DWORD WINAPI threadProc(void* v)
    {

    ThreadData* data = reinterpret_cast<ThreadData*>(v);
    if( !data )
        return 0;

    // tell the main thread that we are up & running
    SetEvent(data->isRunning_);

    // do your work here...

    return 1;
}

int main()
{
    // must use heap-based allocation here so that we can transfer ownership
    // of this ThreadData object to the worker thread.  In other words, 
    // the threadProc() function will own & deallocate this resource when it's
    // done with it.
    ThreadData * data = new ThreadData;
    data->isRunning_ = CreateEvent(0, 1, 0, 0);

    // kick off the new thread, passing the thread data
    DWORD id = 0;
    HANDLE thread = CreateThread(0, 0, threadProc, reinterpret_cast<void*>(data), 0, &id);

    // wait for the worker thread to get up & running
    //
    // in real code, you need to check the return value from WFSO and handle it acordingly.  
    // Here I assume the retval is WAIT_OBJECT_0, indicating that the data->isRunning_ event 
    // has become signaled
    WaitForSingleObject(data->isRunning_,INFINITE); 

    // we're done, wait for the thread to die
    WaitForSingleObject(thread, INFINITE);
    CloseHandle(thread);

    return 0;

}

#4


A common problem with thread startup is that the arguments passed exist on only the stack in the calling function. Thread startup is often deferred, such that the calling function returns and it is only some time later the thread actually starts - by which time the arguments are no longer in existence.

线程启动的一个常见问题是传递的参数仅存在于调用函数的堆栈中。线程启动通常是延迟的,这样调用函数就会返回,并且只是一段时间后线程实际启动 - 这时参数不再存在。

One solution to this is to create an event and then start the thread, passing the event as one of the arguments. The starting function then waits on the event, which is signalled by the thread when it has completed startup.

对此的一个解决方案是创建一个事件,然后启动该线程,将事件作为参数之一传递。然后,启动函数等待事件,该事件在完成启动时由线程发出信号。

#5


You can pass the parameters as members of the thread class. The thread which creates the thread can presumably call other methods and/or call member functions before the thread starts. Therefore it can populate whatever members are necessary for it to work. Then when the run method is called, it will have the necessary info to start up.

您可以将参数作为线程类的成员传递。在线程启动之前,创建线程的线程可能会调用其他方法和/或调用成员函数。因此,它可以填充其工作所需的任何成员。然后,当调用run方法时,它将具有启动所需的信息。

I am assuming that you will use a separate object for each thread.

我假设你将为每个线程使用一个单独的对象。

You would normally put all the threads you create into an array, vector etc.

您通常会将您创建的所有线程放入数组,向量等。

#6


It is ok to pass them via constructor. Just be sure that pointers will live longer than the thread.

可以通过构造函数传递它们。请确保指针的活动时间比线程长。

#7


Well, I'd prefer to put the parameters in the Start() method, so you can have a protected constructor, and doesn't have to cascade the parameters through derived class constructor.

好吧,我更喜欢将参数放在Start()方法中,因此您可以拥有受保护的构造函数,而不必通过派生类构造函数级联参数。

I'd prolly let my decleration look something like this:

我会让我的变相看起来像这样:

class Thread
{
public:
   virtual void Start(int parameterCount, void *pars);
protected:
   Thread();
   virtual void run(int parameterCount, void *pars) = 0;
}

Just make sure that your parameters are somehow contracted, e.g. #1 will be int, #2 will be a double etc. etc. :)

只需确保您的参数以某种方式签约,例如#1将是int,#2将是double等等。:)