2016-04-14 20 views
1

Ich versuche, eine private Member-Funktion (sollte nicht als öffentlich oder geschützt verfügbar sein) als ein Worker-Element mit der Win32-Funktion QueueUserWorkItem() aufrufen. Ich weiß, dass ich das schon einmal gemacht habe und es war einfach, aber jetzt kann ich dieses Schnipsel nicht finden, noch kann ich bind() Voodoo arbeiten lassen. Also für die Zwecke dieser Frage der Klasse:Win32 QueueUserWorkItem() mit einer privaten Memberfunktion aufrufen

class Arbitrary { 

    public: 
     Arbitrary() ; 
     ~Arbitrary() ; 

     bool UsefulPublicFunction(unsigned uParameter) ; 

    protected: 

    private: 
     void PrivateWorkItem(void* pVoid) ; 
} ; 

Und innen UsefulPublicFunction() könnten wir sehen:

LPTHREAD_START_ROUTINE pThreadStartRoutine ; 
ULONG uFlags = 0 ; 
void* pContext = nullptr ; 

if (QueueUserWorkItem(pThreadStartRoutine, pContext, uFlags)) { 
    //blah blah blah 
} 

Wo ich scheine in dem Unkraut zu gehen sind mit der Zuordnung zu pThreadStartRoutine mit so etwas wie :

pThreadStartRoutine = std::bind<&Arbitrary::PrivateWorkItem, this, std::placeholders::_1> ; 

ich erkennen, dass die Signatur für PrivateWorkItem wahrscheinlich ändern sollte:

private: 
    DWORD WINAPI PrivateWorkItem(void* pVoid) ; 

Auch mit dieser Änderung keine Freude. VS2015 hasst wirklich die Art, wie ich bind() benutze.

Wie soll meine Zuordnung zu pThreadStartRoutine aussehen?

+0

Es wäre hilfreich zu wissen, welche Fehler Sie sehen. –

+0

Die Fehlermeldung wurde angefordert ... für mich war es nutzlos - vielleicht macht es für Sie Sinn: "keine Instanz der überladenen Funktion" std :: bind "entspricht dem erforderlichen Typ" – BenWestbrook

Antwort

0

Dies scheint zu funktionieren:

#include <Windows.h> 

#include <stdio.h> 

#include <functional> 

using namespace std::placeholders; 

class Arbitrary { 

    public: 

     bool UsefulPublicFunction(int uParameter); 

    protected: 

    private: 
     typedef std::function<void (void)> CallbackType; 
     static DWORD WINAPI ProcessWorkItem(void* pVoid); 
     void PrivateWorkItem1(int arg1, int arg2); 
     void PrivateWorkItem2(char * arg1); 
}; 

void Arbitrary::PrivateWorkItem1(int arg1, int arg2) 
{ 
    printf("Numbers are %u %u\n", arg1, arg2); 
    return; 
} 

void Arbitrary::PrivateWorkItem2(char * arg1) 
{ 
    printf("String is %s\n", arg1); 
    return; 
} 

DWORD WINAPI Arbitrary::ProcessWorkItem(void* pVoid) 
{ 
    CallbackType * callback = static_cast<CallbackType *>(pVoid); 
    (*callback)(); 
    delete callback; 
    return 0; 
} 

bool Arbitrary::UsefulPublicFunction(int param1) 
{ 
    QueueUserWorkItem(&ProcessWorkItem, new CallbackType(std::bind(&Arbitrary::PrivateWorkItem1, this, param1, 7)), 0); 

    QueueUserWorkItem(&ProcessWorkItem, new CallbackType(std::bind(&Arbitrary::PrivateWorkItem2, this, (char *)"This is my string")), 0); 

    Sleep(1000); 
    return true; 
} 

int main(int argc, char ** argv) 
{ 
    Arbitrary x; 

    x.UsefulPublicFunction(5); 

    return 0; 
} 
+0

Super! Vielen Dank. – BenWestbrook

+0

Sorry, ich habe noch nicht genug Punkte, um die "Punktzahl" Harry zu treffen. – BenWestbrook

1

etwas ähnliche stattdessen versuchen:

class Arbitrary { 

    public: 
     Arbitrary() ; 
     ~Arbitrary() ; 

     bool UsefulPublicFunction(unsigned uParameter); 

    protected: 

    private: 
     static DWORD WINAPI PrivateWorkItem(void* pVoid) ; 
     void PrivateFunction(); 
} ; 

DWORD WINAPI Arbitrary::PrivateWorkItem(void* pVoid) 
{ 
    static_cast<Arbitrary*>(pVoid)->PrivateFunction(); 
    return 0; 
} 

... 

if (QueueUserWorkItem(&PrivateWorkItem, this, 0)) { 
    //blah blah blah 
} 
+0

Das fühlt sich eher klobig und zu Ich, scheint nicht so zuverlässig aus einer langfristigen Perspektive der Code-Wartung - vor allem, weil es tatsächlich eine Reihe von einzigartigen privaten Worker-Funktionen in der Klasse gibt. Aber ja, ich habe es so gemacht, wie du es vorschlägst und ich habe es auch deklariert und automatisch mit der richtigen Signatur versehen und dann einfach mit memcpy in pThreadStartRoutine geworfen, aber das scheint mir genauso klobig zu sein. Auf den Punkt scheint die Verwendung von Bindung gerade in Bezug auf Absicht, wenn ein Praktikant diesen Code in 10 Jahren hält. – BenWestbrook

+0

Sie können 'std :: bind()' nicht wirklich verwenden, um Win32-API-Callback-Funktionen einzurichten (siehe http://stackoverflow.com/questions/18161680/). Was ich oben gezeigt habe, ist die "sauberste" Lösung, die keine hässlichen Hacks beinhaltet. –

+0

Sie könnten vermutlich eine einzelne statische Funktion verwenden, die einen Zeiger auf einen von std :: bind generierten Weiterleitungsaufruf-Wrapper akzeptiert. Nur so lange der Aufruf des Wrappers von C++ und nicht von Windows kommt. –

Verwandte Themen