Auf Beendigung des letzten Threads warten...



  • Habt ihr eine Idee, wie ich auf die Beendigung des letzten Threads warten kann, also, wie das Hauptprogramm erst dann schließt, wenn alle Tasks/Threads fertig sind?

    #include <windows.h>
    #include <iostream>
    #include <string>
    
    #include <chrono>
    #include <thread>
    
    DWORD WINAPI myThread(LPVOID lpParameter)
    {
        std::string s = *((std::string*)lpParameter);
        SYSTEMTIME time1;
        GetSystemTime(&time1);
    
        SHELLEXECUTEINFO ShExecInfo = { 0 };
        ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
        ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
        ShExecInfo.hwnd = NULL;
        ShExecInfo.lpVerb = NULL;
        ShExecInfo.lpFile = s.c_str();
        ShExecInfo.lpParameters = "";
        ShExecInfo.lpDirectory = NULL;
        ShExecInfo.nShow = SW_SHOW;
        ShExecInfo.hInstApp = NULL;
        ShellExecuteEx(&ShExecInfo);
        WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
    
        SYSTEMTIME time2;
        GetSystemTime(&time2);
        std::cout << s << " : ";
        std::cout << ((time2.wSecond * 1000) + time2.wMilliseconds - (time1.wSecond * 1000) - time1.wMilliseconds) << " Milliseconds" << std::endl;
        return 0;
    }
    
    int main(int argc, char* argv[])
    {
        using namespace std;
        for (int i = 1; i < argc; i += 2) {
            string s = string(argv[i]);
            int sleepTime = atoi(argv[i + 1]);
            DWORD myThreadID;
            HANDLE myHandle = CreateThread(0, 0, myThread, &s, 0, &myThreadID);
            CloseHandle(myHandle);
            this_thread::sleep_for(chrono::seconds(sleepTime));
        }
        return 0;
    }
    

    Kompiliert es mit -std=c++11.

    Beispiel: a.exe b.exe 5 c.exe 10

    a.exe ruft b.exe auf, wartet dann 5 Sekunden, und ruft c.exe auf, und wartet dann nochmal 10 Sekunden. (b.exe und c.exe können beliebige Programme sein, die irgendetwas tun). Wenn b.exe und/oder c.exe innerhalb von 15 Sekunden fertig ist, wird dessen Ausführungszeitdauer ausgegeben. Aber a.exe wird in jeden Fall nach 15 Sekunden beendet. 😞


  • Mod

    Es gibt buchstäblich Funktionen zum Warten auf Handles.WaitForSingleObject, WaitForMultipleObjects. Die du schon nutzt. Oder wohl eher irgendwo abgeschrieben hast, sonst wüsstest du es schließlich.

    Vielleicht möchtest du die Anleitung zu Winapi-Threads lesen, bevor du wild experimentierst? Oder die high-level Funktionen der Programmiersprache deiner Wahl benutzen? Du includest ja schon C++-Threads.



  • Sag mir doch einfach, ob Zeile 42 richtig/falsch ist... Anstatt mir Unkenntnis oder Blödheit zu unterstellen...

    Ach, weißte was, vergiss es einfach, ich suche auf Stack Overflow danach, das erspart mir solche schlechtgelaunte Menschen, die es wahrscheinlich selber nicht besser wissen.



  • Das funktioniert jetzt wenigstens:

    #include <windows.h>
    #include <iostream>
    #include <string>
    
    #include <chrono>
    #include <thread>
    
    DWORD WINAPI myThread(LPVOID lpParameter)
    {
        std::string s = *((std::string*)lpParameter);
        std::chrono::milliseconds ms1 = std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::system_clock::now().time_since_epoch());
    
        SHELLEXECUTEINFO ShExecInfo = { 0 };
        ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
        ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
        ShExecInfo.hwnd = NULL;
        ShExecInfo.lpVerb = NULL;
        ShExecInfo.lpFile = s.c_str();
        ShExecInfo.lpParameters = "";
        ShExecInfo.lpDirectory = NULL;
        ShExecInfo.nShow = SW_SHOW;
        ShExecInfo.hInstApp = NULL;
        ShellExecuteEx(&ShExecInfo);
        WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
    
        std::chrono::milliseconds ms2 = std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::system_clock::now().time_since_epoch());
        std::cout << s << " : ";
        std::cout << (ms2 - ms1).count() << " Milliseconds" << std::endl;
        return 0;
    }
    
    int main(int argc, char* argv[])
    {
        using namespace std;
        int n1 = (argc - 1) / 2;
        HANDLE handles[n1];
        for (int i = 1; i < argc; i += 2) {
            string s = string(argv[i]);
            int sleepTime = atoi(argv[i + 1]);
            DWORD myThreadID;
            handles[(i - 1) / 2] = CreateThread(0, 0, myThread, &s, 0, &myThreadID);
            this_thread::sleep_for(chrono::seconds(sleepTime));
        }
        WaitForMultipleObjects(n1, handles, TRUE, INFINITE);
        for (int i = 0; i < n1; i++) {
            CloseHandle(handles[i]);
        }
        return 0;
    }
    

    Beispiel:

    >a.exe b.exe 2 b.exe 2 b.exe 2
    b.exe : 6629 Milliseconds
    b.exe : 17970 Milliseconds
    b.exe : 23373 Milliseconds
    
    


  • @EinNutzer0 sagte in Auf Beendigung des letzten Threads warten...:

    Das funktioniert jetzt wenigstens:
    ...

    WaitForMultipleObjects(...
    

    ...

    Genau das hat SeppJ ja vorgeschlagen:

    @SeppJ sagte in Auf Beendigung des letzten Threads warten...:

    Es gibt buchstäblich Funktionen zum Warten auf Handles.WaitForSingleObject, WaitForMultipleObjects.



  • @Belli sagte in Auf Beendigung des letzten Threads warten...:

    Genau das hat SeppJ ja vorgeschlagen:

    Ja, aber er wirft mir vor, alles abzuschreiben... Ist es schlimm, wenn man nicht jede Funktion kennt?



  • @EinNutzer0
    Sei nicht so ein Mimöschen.
    Abschreiben ist ja nicht per se was Schlimmes.

    Außerdem war das kein Vorwurf, eher eine Vermutung, von mir aus auch eine Unterstellung, na und?

    Trotzdem war doch der entscheidende Hinweis dabei!



  • @Belli Ja, schon gut.

    Hier ist es nochmal in Schön und mit Prozess-ID:

    #include <windows.h>
    #include <iostream>
    #include <string>
    
    #include <chrono>
    #include <thread>
    
    DWORD WINAPI myThread(LPVOID lpParameter)
    {
        using namespace std;
        string s = *((string*)lpParameter);
        chrono::milliseconds ms1 = chrono::duration_cast<chrono::milliseconds>(
            chrono::system_clock::now().time_since_epoch());
    
        SHELLEXECUTEINFO ShExecInfo = { 0 };
        ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
        ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
        ShExecInfo.hwnd = NULL;
        ShExecInfo.lpVerb = NULL;
        ShExecInfo.lpFile = s.c_str();
        ShExecInfo.lpParameters = "";
        ShExecInfo.lpDirectory = NULL;
        ShExecInfo.nShow = SW_SHOW;
        ShExecInfo.hInstApp = NULL;
        ShellExecuteEx(&ShExecInfo);
        WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
    
        chrono::milliseconds ms2 = chrono::duration_cast<chrono::milliseconds>(
            chrono::system_clock::now().time_since_epoch());
        cout << s << " : ";
        cout << GetProcessId(ShExecInfo.hProcess) << " : ";
        cout << (ms2 - ms1).count() << " Milliseconds" << endl;
        return 0;
    }
    
    int main(int argc, char* argv[])
    {
        using namespace std;
        int n1 = (argc - 1) / 2;
        HANDLE handles[n1];
        for (int i = 1; i < argc; i += 2) {
            string s = string(argv[i]);
            int sleepTime = atoi(argv[i + 1]);
            DWORD myThreadID;
            handles[(i - 1) / 2] = CreateThread(0, 0, myThread, &s, 0, &myThreadID);
            this_thread::sleep_for(chrono::seconds(sleepTime));
        }
        WaitForMultipleObjects(n1, handles, TRUE, INFINITE);
        for (int i = 0; i < n1; i++) {
            CloseHandle(handles[i]);
        }
        return 0;
    }
    

    Aber es gibt noch ein Problem: a.exe b.exe 2 b.exe 2 b.exe 2 funktioniert, a.exe b.exe 2 b.exe 2 b.exe 0 funktioniert hingegen nicht. Also, "warte nach dem letzten Aufruf nicht" funktioniert nicht, das dritte b.exe-Fenster wird nicht geöffnet.


  • Mod

    @EinNutzer0 sagte in Auf Beendigung des letzten Threads warten...:

    handles[(i - 1) / 2]

    Erklär mal. Und nach der Erklärung, probier auch einmal aus, ob deine Annahmen überhaupt stimmen.



  • Das sollte, wegen i += 2 so passen (wenn auch nicht sehr schön).

    Aber das Programm hat wegen der Übergabe von &s (lokale Variable) an die Thread-Funktion undefiniertes Verhalten:

    string s = string(argv[i]);
    int sleepTime = atoi(argv[i + 1]);
    DWORD myThreadID;
    handles[(i - 1) / 2] = CreateThread(0, 0, myThread, &s, 0, &myThreadID);
    this_thread::sleep_for(chrono::seconds(sleepTime));
    

    Durch den 'sleep_for' wird zwar das Timing ein bißchen abgemildert, aber garantiert ist es nicht, daß die Thread-Funktion auch rechtzeitig aufgerufen wird und der Parameter bei

    std::string s = *((std::string*)lpParameter);
    

    korrekt übernommen wird (das erklärt dann wohl auch das Verhalten bei sleepTime = 0).
    Warum überhaupt die Konvertierung zu einem std::string? Einfach argv[i] übergeben (hier ist garantiert, daß diese Arraywerte während der main-Funktion erhalten bleiben).

    PS:

    int n1 = (argc - 1) / 2;
    HANDLE handles[n1];
    

    d.h. die Benutzung von VLA ist kein Standard-C++.



  • Naja, das argc ist eh wackelig.
    Was, wenn 1 Argument übergeben wird, d.h. argc==2.

    Dann: n1 == (2-1)/2 == 1/2 == 0

    VLAs der Größe 0 sind doch nicht erlaubt, oder? Aber auch egal, denn:
    for (int i = 1; i < argc; i += 2) ist dann 1 < 2 im ersten Durchlauf, also true, und dann crasht es eben danach - sowohl beim atoi(argv[i + 1]); als auch beim handles[0] = ....



  • Vielen Dank für eure Ideen und Vorschläge, ich werde das nachher miteinbeziehen und eine neue Version posten. @SeppJ Sorry, dass ich dich angemault hatte, das wollte ich nicht.

    Schönen Abend. 🙂



  • Btw. die eigene, ausführbare exe Datei kreidet mir Windows als Virus an, wenn ich sie ins Internet hochladen, und wieder herunterladen möchte, und verhindert den kompletten Download... Virustotal meldet "sauber".

    Was ist so brisant an diesen Code?

    Kann man in diesem Forum einen Dateianhang hinzufügen?



  • @EinNutzer0 sagte in Auf Beendigung des letzten Threads warten...:

    kreidet mir Windows als Virus an

    Genaue Meldung? Copy&Paste.


  • Mod

    @EinNutzer0 sagte in Auf Beendigung des letzten Threads warten...:

    Kann man in diesem Forum einen Dateianhang hinzufügen?

    Nein. Wenn es wirklich wichtig ist, kannst du einen externen Hoster nutzen und verlinken. Falls dein Plan ist, dass sich jemand deine Executable runterlädt oder gar ausführt: Das wird wahrscheinlich niemand tun.







  • Posting here is generally a waste of time, since no one here truly works for Microsoft, especially the more technical security groups involved in the operation and support for Defender itself. We're all mostly either consumer volunteers or contract workers who provide first-level support for Microsoft's products.

    🤪

    Heißt auf Deutsch, der KI, Heuristik oder wie man es nennen möchte, gefällt nicht, was ich tue. Aber ich freue mich, meinen ersten eigenen Virus entworfen zu haben. 🙂 (Sogar schwerwiegend...)



  • Jetzt funktioniert's, Freunde:

    #include <windows.h>
    #include <iostream>
    #include <string>
    
    #include <chrono>
    #include <thread>
    
    DWORD WINAPI myThread(LPVOID lpParameter)
    {
        using namespace std;
        char* argv = *((char**)lpParameter);
        chrono::milliseconds ms1 = chrono::duration_cast<chrono::milliseconds>(
            chrono::system_clock::now().time_since_epoch());
    
        SHELLEXECUTEINFO ShExecInfo = { 0 };
        ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
        ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
        ShExecInfo.hwnd = NULL;
        ShExecInfo.lpVerb = NULL;
        ShExecInfo.lpFile = argv;
        ShExecInfo.lpParameters = "";
        ShExecInfo.lpDirectory = NULL;
        ShExecInfo.nShow = SW_SHOW;
        ShExecInfo.hInstApp = NULL;
        ShellExecuteEx(&ShExecInfo);
        WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
    
        chrono::milliseconds ms2 = chrono::duration_cast<chrono::milliseconds>(
            chrono::system_clock::now().time_since_epoch());
        cout << argv << " : ";
        cout << GetProcessId(ShExecInfo.hProcess) << " : ";
        cout << (ms2 - ms1).count() << " Milliseconds" << endl;
        return 0;
    }
    
    int main(int argc, char* argv[])
    {
        if (argc <= 1 || argc % 2 != 1) {
            return 0;
        }
        using namespace std;
        const int n1 = (argc - 1) / 2;
        HANDLE handles[n1];
        for (int i = 1; i < argc; i += 2) {
            int sleepTime = atoi(argv[i + 1]);
            DWORD myThreadID;
            handles[(i - 1) / 2] = CreateThread(0, 0, myThread, &argv[i], 0, &myThreadID);
            this_thread::sleep_for(chrono::seconds(sleepTime));
        }
        WaitForMultipleObjects(n1, handles, TRUE, INFINITE);
        for (int i = 0; i < n1; i++) {
            CloseHandle(handles[i]);
        }
        return 0;
    }
    

    War echt so, dass die garbage collection gegriffen hat... Btw. warum muss ich erst nach char** und dann nach * casten? LPVOID, DWORD und WINAPI ist mir sehr suspekt.



  • @EinNutzer0 sagte in Auf Beendigung des letzten Threads warten...:

    garbage collection

    what?

    @EinNutzer0 sagte in Auf Beendigung des letzten Threads warten...:

    Btw. warum muss ich erst nach char** und dann nach * casten?

    Warum übergibst du überhaupt &argv[i] und nicht argv[i]?


Log in to reply