在C ++中制作类似Java的可运行类时出现问题

NT_*_*TEM 3 c++ multithreading

我一直试图创建一个可运行的类,以便像java-folks那样连接多线程类。但是我似乎无法在虚拟函数运行时使用_beginthread。我收到以下错误:

' beginthread':无法将参数1从'void( _cdecl Runnable :: *)(void *)' 转换为'void(__cdecl *)(void *)'

#include "CriticalSection.h"
#include <stdio.h>
#include <conio.h>
#include <process.h>

class Runnable{
private:
    Runnable() { _beginthread(&Runnable::Run,0,(void*)0); }
    ~Runnable();
    virtual void __cdecl Run ( void* ) = 0;
};

int main(){
    //CriticalSection crt;
    //ErrorHandler err;
    //LockSection lc(&crt,&err);

    while(!kbhit());
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*eas 5

有两种实现多线程库的方法,这两种方法都在Java中使用,但C ++的变体略有不同。由于您似乎了解Java,因此我将在其中讨论方法:

从线程派生

在这种方法中,有一个代表线程的基类,您可以从该基类继承并实现一个在线程启动时将被调用的方法。基线程类提供对线程的控制,派生类实现一个run(或等效方法)。基本线程类不得启动实际线程,而应让用户代码通过member method启动它start。这样做的原因是,如果基线程类启动了该线程,则新产生的线程可能会在创建完整对象之前尝试调用重写的方法。在C ++中的基线程类中调用重写器,或run在Java中对尚未初始化的对象调用方法的最终重写器,这具有讨厌的副作用。-在两种情况下都不安全。

可运行的界面

为了减少引起不确定行为的可能性并分离责任,第二种方法将线程控制与要在新生成的线程中运行的代码的实现区分开来。创建了一个线程类,但并不意味着将其用作基类。而是为Runnable对象提供接口。用户代码将从该接口派生,并将一个对象传递给线程类。该设计确保了先前的错误无法完成,因为Runnable必须先完全创建该错误,然后再将其传递给线程。

可运行接口的现代C ++方法

新的标准线程库(和增强线程)提供了与Runnable接口相似的方法,但有一些区别。首先是用户代码不需要完全填充一个具体的接口,但实际上可以告诉线程库要运行该类的哪种方法以及带有哪些参数。这是通过在线程类的构造函数中应用类型擦除来实现的,其中删除了用户参数的确切类型,以便以后在线程内部使用。这具有与Runnable版本-确保在生成线程之前完全创建对象。同时,它消除了必须实现确切接口的要求,这意味着您将能够使用自由函数或类的成员函数以及将在其上调用该成员函数的实例。 ,或实现operator()... 的函子

如果要使用C ++进行编码,建议您使用最后一种方法,因为这对于用户代码来说是最灵活的,同时,它比您尝试做的事更安全。也就是说,不要重新发明轮子,有很好的思想C ++线程库(如果有的话可以使用C ++ 11,如果没有的话则可以提高-或Poco或ACE ...)可以避免许多陷阱。

要记住的重要一点是,无论采用哪种方法,都必须确保新线程不会尝试在未完全创建的对象中调用虚函数,因为这将导致未定义行为。