【问题标题】:Calling PThread from Windows Form Class to a function inside the Windows Form Class从 Windows 窗体类调用 PThread 到 Windows 窗体类中的函数
【发布时间】:2012-03-31 11:54:40
【问题描述】:

我在 Visual Studio 2008 Professional 中的 Windows 窗体上使用 pthread,但在示例源代码中显示的行中出现错误。可能是因为它是 C++/CLI,因为这通常在常规类中工作。问题出在这一行:

((TestGUI*)context)->TestxFunc();

在函数StaticCallFunc中

public ref class TestGUI : public System::Windows::Forms::Form {
        /...
    public:

void TestxFunc(std::string test, std::string test2){
        this->btn_next->Enabled = false;
        cout << "HI, Test: " << test << "," << " Test 2: " << test2 << endl;

 }

static void *StaticCallFunc(void *context){
    std::string test = "foo";
    std::string test2 = "bar";
    printf("\nStarting Thread");
    ((TestGUI*)context)->TestxFunc(); //Line with the error down.
    return 0;

} 

System::Void tester_Click(System::Object^  sender, System::EventArgs^  e) {
      pthread_t t;
      pthread_create(&t, NULL, &TestGUI::StaticCallFunc, this);
}

//...

错误 C3699: '' : 不能在类型 'Test::TestxFunc' 1 上使用此间接寻址> 编译器将 '*' 替换为 '^' 以继续解析

错误 C2227:'->TestxFunc' 的左侧必须指向 类/结构/联合/泛型类型

我该怎么做才能解决这个问题?这个调用通常适用于常规类,但在 Windows 窗体中它确实没有

【问题讨论】:

    标签: c++ visual-studio-2008 visual-c++ pthreads


    【解决方案1】:

    由于TestGUI 是一个CLI/C++ 类,你应该使用^ 而不是* 来取消引用它的指针,但这不是唯一的问题。您似乎想在 pthread 中执行 CLI/C++ 类成员方法。要使其工作,您可以尝试以下方式:

    *从 TestGUI 类中删除 StaticCallFunc 并使其成为全局方法。
    *要将TestGUI 指针传递给非托管函数,您可以使用gcroot。所以定义一个容器类,例如PtrContainergcroot 作为成员。

    //dont forget forward declerations
    void *StaticCallFunc(void *context); //forward decleration
    ref class TestGUI; //forward decleration
    
    //Define a simple argument class to pass pthread_create
    struct PtrContainer{
         gcroot<TestGUI^> guiPtr; //you need to include vcclr.h for this
    };
    

    当您绑定到pthread_create 时,您可以使用PtrContainer,如下所示:

    System::Void tester_Click(System::Object^  sender, System::EventArgs^  e) {
    
        //init. container pointer,
        //we use dynamically allocated object because the thread may use it after this method return
        PtrContainer* ptr = new PtrContainer;
        ptr->guiPtr = this;
    
        pthread_t t;
        pthread_create(&t, NULL, StaticCallFunc, ptr );
    }
    

    你应该删除驱动方法中的容器指针 (StaticCallFunc) 完成后:

    void *StaticCallFunc(void *context){
        std::string test = "foo";
        std::string test2 = "bar";
        printf("\nStarting Thread");
        PtrContainer* ptr = reinterpret_cast<PtrContainer*>(context);
        ptr->guiPtr->TestxFunc(test, test2);
    
        //dont forget to delete the container ptr.
        delete ptr;
    
        return 0;
    }
    

    还有一个注意事项;当您以多线程方式访问 .NET gui 组件时,you must be careful to make calls to your controls in a thread-safe way.


    编辑:我添加了以下在 Visual Studio 11、Windows7 下编译和工作的完整源代码。

    //sample.cpp
    
    #include <iostream>
    #include <string>
    #include <vcclr.h>
    #include <sstream>
    using namespace std;
    using namespace System;
    using namespace System::Windows::Forms;
    
    #include "pthread.h"
    #include <stdio.h>
    
    #define PTW32_THREAD_NULL_ID {NULL,0}
    #define int64_t _int64
    
    void *StaticCallFunc(void *context); //forward decleration
    ref class TestGUI; //forward decleration
    
    //Define a simple argument class to pass pthread_create
    struct PtrContainer{
        gcroot<TestGUI^> guiPtr; //you need to include vcclr.h for this
    };
    
    ref class TestGUI : public System::Windows::Forms::Form  
    {
    public:
        TestGUI(void) {
            this->Click += gcnew System::EventHandler(this, &TestGUI::tester_Click );
        }
    
        void TestxFunc(std::string test, std::string test2){
                cout << "HI, Test: " << test << "," << " Test 2: " << test2 << endl;
        }
    
        System::Void tester_Click(System::Object^  sender, System::EventArgs^  e) {
            //init. container pointer,
            //we use dynamically allocated object because the thread may use it after this method return
            PtrContainer* ptr = new PtrContainer;
            ptr->guiPtr = this;
    
            pthread_t t;
            pthread_create(&t, NULL, StaticCallFunc, ptr );
        }
    };
    
    void *StaticCallFunc(void *context){
        std::string test = "foo";
        std::string test2 = "bar";
        printf("\nStarting Thread");
        PtrContainer* ptr = reinterpret_cast<PtrContainer*>(context);
        ptr->guiPtr->TestxFunc(test, test2);
    
        //dont forget to delete the container ptr.
        delete ptr;
        return 0;
    }
    
    int main()
    {
        TestGUI^ testGui = gcnew TestGUI();
        testGui->ShowDialog();
        return 0;
    }
    

    编译:

    /analyze- /clr /Od /nologo /MDd /Gm- /Fa".\Debug\" /I".." /Oy- /FU"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\mscorlib.dll" /FU"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll" /FU"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Windows.Forms.dll" /Zc:forScope /Fo".\Debug\" /Gy- /Fp".\Debug\Debug.pch" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "CLEANUP_C" /D "_VC80_UPGRADE=0x0600" /D "_MBCS" /WX /errorReport:queue /GS /Fd".\Debug\" /fp:precise /FR".\Debug\" /W3 /Z7 /Zc:wchar_t /EHa 
    

    【讨论】:

    • 我测试了自己,但在“ptr->guiPtr = this;”的行中出现错误说->错误C2679:二进制'=':找不到采用右侧操作数类型的运算符
    • @Grego 我已经添加了完整的源文件,但我在只有我拥有的 VS 11 Beta 下对其进行了测试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-31
    • 2020-05-15
    相关资源
    最近更新 更多