Thread Management



  • falsch schrieb:

    314159265358979 schrieb:

    dot schrieb:

    314159265358979 schrieb:

    Wenn der Main-Thread endet, enden alle Threads.

    Das ist eine Designfrage des Betriebssystems. Unter Windows z.B. endet ein Prozess erst wenn der letzte Thread des Prozesses endet.

    Nein. Unter Windows ist das genau nicht so.

    Du hast unrecht!
    http://msdn.microsoft.com/en-us/library/ms686722(v=vs.85).aspx

    Probiers doch aus, du wirst feststellen, dass dem so ist. Sowohl mit pthreads, als auch mit boost.



  • Ja weil die CRT ExitProcess aufruft. Das ändert aber nichts daran das deine Aussage falsch ist.



  • Welche CRT? 😃



  • 314159265358979 schrieb:

    Nein. Unter Windows ist das genau nicht so.

    Doch, siehe Link vom Vorposter.

    zeusosc schrieb:

    Du kannst ja auch einen Thread erstellen, und das letzte Handle von diesem schließen. der Thread ist dann nicht mehr mit diesem Prozess assoziiert, läuft aber noch!

    Woher hast du das denn? Das kann eigentlich nur Blödsinn sein, würde das gehen so würde das bedeuten man kann Threads ohne Kontext erschaffen was a) komplett sinnlos wäre und b) zwangsweise crashen würde.



  • 314159265358979 schrieb:

    Welche CRT? 😃

    Hast du den Link auch nur kurz überflogen?



  • Der von "falsch" gepostete Link sollte eigentlich alles klären.

    Unter Windows endet ein Prozess, wenn alle seine Threads beendet wurden.



  • Bei mir hat der Prozess immer geendet, wenn der MainThread beendet wurde. Discuss!



  • Also wenn ich das MSDN Beispiel so änder, dass die Threads ewig laufen, wird das Programm trotzdem sofort beim return (Zeile 72) aus main beenden, auch wenn ich die anderen Threads nicht beende.

    #include <windows.h>
    #include <tchar.h>
    #include <strsafe.h>
    
    #define MAX_THREADS 3
    #define BUF_SIZE 255
    
    DWORD WINAPI MyThreadFunction( LPVOID lpParam );
    void ErrorHandler(LPTSTR lpszFunction);
    
    // Sample custom data structure for threads to use.
    // This is passed by void pointer so it can be any data type
    // that can be passed using a single void pointer (LPVOID).
    typedef struct MyData {
        int val1;
        int val2;
    } MYDATA, *PMYDATA;
    
    int _tmain()
    {
        PMYDATA pDataArray[MAX_THREADS];
        DWORD   dwThreadIdArray[MAX_THREADS];
        HANDLE  hThreadArray[MAX_THREADS]; 
    
        // Create MAX_THREADS worker threads.
    
        for( int i=0; i<MAX_THREADS; i++ )
        {
            // Allocate memory for thread data.
    
            pDataArray[i] = (PMYDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                    sizeof(MYDATA));
    
            if( pDataArray[i] == NULL )
            {
               // If the array allocation fails, the system is out of memory
               // so there is no point in trying to print an error message.
               // Just terminate execution.
                ExitProcess(2);
            }
    
            // Generate unique data for each thread to work with.
    
            pDataArray[i]->val1 = i;
            pDataArray[i]->val2 = i+100;
    
            // Create the thread to begin execution on its own.
    
            hThreadArray[i] = CreateThread( 
                NULL,                   // default security attributes
                0,                      // use default stack size  
                MyThreadFunction,       // thread function name
                pDataArray[i],          // argument to thread function 
                0,                      // use default creation flags 
                &dwThreadIdArray[i]);   // returns the thread identifier 
    
            // Check the return value for success.
            // If CreateThread fails, terminate execution. 
            // This will automatically clean up threads and memory. 
    
            if (hThreadArray[i] == NULL) 
            {
               ErrorHandler(TEXT("CreateThread"));
               ExitProcess(3);
            }
        } // End of main thread creation loop.
    
        // Wait until all threads have terminated.
    
        return 0;
        WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);
    
        // Close all thread handles and free memory allocations.
    
        for(int i=0; i<MAX_THREADS; i++)
        {
            CloseHandle(hThreadArray[i]);
            if(pDataArray[i] != NULL)
            {
                HeapFree(GetProcessHeap(), 0, pDataArray[i]);
                pDataArray[i] = NULL;    // Ensure address is not reused.
            }
        }
    
        return 0;
    }
    
    DWORD WINAPI MyThreadFunction( LPVOID lpParam ) 
    { 
        HANDLE hStdout;
        PMYDATA pDataArray;
    
        TCHAR msgBuf[BUF_SIZE];
        size_t cchStringSize;
        DWORD dwChars;
    
        // Make sure there is a console to receive output results. 
    
        hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
        if( hStdout == INVALID_HANDLE_VALUE )
            return 1;
    
        // Cast the parameter to the correct data type.
        // The pointer is known to be valid because 
        // it was checked for NULL before the thread was created.
    
        pDataArray = (PMYDATA)lpParam;
    
        // Print the parameter values using thread-safe functions.
    
    	while(true)
    	{
    		StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d\n"), 
    			pDataArray->val1, pDataArray->val2); 
    		StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);
    		WriteConsole(hStdout, msgBuf, (DWORD)cchStringSize, &dwChars, NULL);
    		Sleep(500);
    	}
        return 0; 
    } 
    
    void ErrorHandler(LPTSTR lpszFunction) 
    { 
        // Retrieve the system error message for the last-error code.
    
        LPVOID lpMsgBuf;
        LPVOID lpDisplayBuf;
        DWORD dw = GetLastError(); 
    
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | 
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            dw,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR) &lpMsgBuf,
            0, NULL );
    
        // Display the error message.
    
        lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
            (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) lpszFunction) + 40) * sizeof(TCHAR)); 
        StringCchPrintf((LPTSTR)lpDisplayBuf, 
            LocalSize(lpDisplayBuf) / sizeof(TCHAR),
            TEXT("%s failed with error %d: %s"), 
            lpszFunction, dw, lpMsgBuf); 
        MessageBox(NULL, (LPCTSTR) lpDisplayBuf, TEXT("Error"), MB_OK); 
    
        // Free error-handling buffer allocations.
    
        LocalFree(lpMsgBuf);
        LocalFree(lpDisplayBuf);
    }
    


  • Wie ich sagte :p



  • Weil der Code innerhalb der Laufzeitbibliothek vereinfacht so aussieht:

    void mainCRTStartup()
    {
        int ret = main(...);
        ExitProcess(ret);
    }
    

    Ohne den Aufruf von ExitProcesss würde der Prozess (unter Windows) weiterlaufen.



  • Welche Laufzeitbibliothek verdammt nochmal -.-
    Bei MinGW exakt selbes verhalten.



  • Ihr habt also quasi recht wenn ihr sagt "unter C++ ist das so".

    Aber das ist nicht das Verhalten des Betriebssystems.



  • Wie kann man das deaktivieren?



  • 314159265358979 schrieb:

    Welche Laufzeitbibliothek verdammt nochmal -.-
    Bei MinGW exakt selbes verhalten.

    Die Laufzeitbibliothen, die auch main() aufruft verdammt nochmal 🙄

    Was du schreibst ist Unsinn, sorry.

    Windows beendet den Prozess nur dann "von selbst", wenn der letzte Thread beendet wurde, egal welcher Thread das ist.

    Dass mit MSVC und MinGW hier das selbe passiert, nämlich das Programm beendet wird wenn die main() Funktion verlassen wird, ist wohl kaum ein Beweis dafür, dass Windows dies machen würde. Das ist einfach so, weil die CRT von sowohl MSVC als auch MinGW hier das selbe tun, nämlich EndProcess aufzurufen.

    ps.: deaktivieren kann man das soweit ich weiss gar nicht. Aber du kannst ein Programm schreiben das die CRT nicht verwendet - such dir die passenden Linker-Flags raus wenn du es probieren willst. Dann wirst sehen, dass Windows sich herzlich wenig darum schert welche Threads noch laufen, so lange noch wenigstens ein laufender Thread da ist.



  • Hm, ok, und wenn ich das Verhalten nicht haben will?



  • 314159265358979 schrieb:

    Hm, ok, und wenn ich das Verhalten nicht haben will?

    Dann musst du in der Doku deiner C++ Implementierung schaun wie du das abschalten kannst, was normalerweise wohl bedeutet dass du auf die Runtime verzichten musst.



  • also habs getested wenn ich ein thread starte und aus dem wieder threads hervorgehen und ich das 1. thread aus dem die anderen gestartet wurden terminiere dann laufen die anderen noch weiter. gibts da ne möglichkeit sie zu beenden wenn der "main" thread auch terminiert wird?



  • du darfst den 1. Thread nicht per TerminateThread beenden, sondern anders...



  • und wie?



  • Ein Thread beendet wenn seine ThreadProc returned. Wenn du willst dass ein Thread beendet dann musst du also dafür sorgen dass seine ThreadProc returned, fertig.


Anmelden zum Antworten