[c++] DLL - Thread korrekt beenden

Hab ich im Büro, kann ich also frühestens am Montag rauskramen. Da hab ich sowas für die serielle Schnittstelle gebraucht.
 
Code:
bool OpenPort()
{

  if ( m_hPort != INVALID_HANDLE_VALUE )
  {
    return false;
  }

  char      szPortName[MAX_PATH];

  dh::Log( "Opening Port (%s)", m_ParameterList.GetParam( "ZVT.COM.Port" ).c_str() );
  wsprintf( szPortName, "\\\\.\\COM%d", GR::Convert::ToU32( m_ParameterList.GetParam( "ZVT.COM.Port" ) ) );
  //wsprintf( szPortName, "COM%d:", m_wPort );

  m_hPort = CreateFile( szPortName,
							          GENERIC_READ    | GENERIC_WRITE,    // access (read-write) mode 
							          0,									                // share mode exclusive-access
							          NULL,                               // pointer to security descriptor 
							          OPEN_EXISTING,                      // how to create 
							          FILE_FLAG_OVERLAPPED,               // file attributes 
							          NULL );                             // handle to file with attributes to copy  

  if ( m_hPort == INVALID_HANDLE_VALUE ) 
  {
    // TODO - GetLastError
    // ERROR_ACCESS_DENIED (5). 
    // Similarly if you by mistake opened a COM port that doesn't exist , you would get ERROR_FILE_NOT_FOUND  
    dh::Log( "Couldn't open port %d", GR::Convert::ToU32( m_ParameterList.GetParam( "ZVT.COM.Port" ) ) );
    return false;
  }

  m_hEventWaitDataReceived = CreateEvent( NULL, TRUE, FALSE, NULL );

  m_hEventDataWritten = CreateEvent( NULL, FALSE, FALSE, NULL );
  memset( &m_ovWrite, 0, sizeof( m_ovWrite ) );
  m_ovWrite.hEvent = m_hEventDataWritten;

  memset( &m_ovRead, 0, sizeof( m_ovRead ) );

  if ( !::SetCommMask( m_hPort, EV_RXCHAR ) )//| EV_TXEMPTY ) )
  {
    dh::Log( "CSerialCommHelper :  Error setting com mask. %x", GetLastError() );
    ClosePort();
		return false;
  }

	COMMTIMEOUTS timeouts;
	
	timeouts.ReadIntervalTimeout					= MAXDWORD; 
	timeouts.ReadTotalTimeoutMultiplier		= 0;
	timeouts.ReadTotalTimeoutConstant			= 0;
	timeouts.WriteTotalTimeoutMultiplier	= 0;
	timeouts.WriteTotalTimeoutConstant		= 0;
	
  if ( !SetCommTimeouts( m_hPort, &timeouts ) )
	{
    dh::Log( "CSerialCommHelper :  Error setting time-outs. %x", GetLastError() );
    ClosePort();
		return false;
	}

  m_hEventCloseWorkerThread = CreateEvent( NULL, TRUE, FALSE, NULL );

  DWORD   dwThreadID = 0;
  m_hWorkerThread = CreateThread( NULL, 0, WorkerThreadHelper, (LPVOID)this, 0, &dwThreadID );
  if ( m_hWorkerThread == NULL )
  {
    dh::Log( "Failed to create worker thread" );
    ClosePort();
    return false;
  }

  if ( !StartThread() )
  {
    ClosePort();
    dh::Log( "StartThread Failed" );
    return false;
  }

  return true;

}



void ClosePort()
{

  dh::Log( "CLosePOrt" );
  SetEvent( m_hEventCloseWorkerThread );

  // ist ein Eigenbau für die Klassen-eigene Thread-Instanz
  ShutDown( 250 );

  dh::Log( "closed" );

  if ( m_hEventCloseWorkerThread )
  {
    CloseHandle( m_hEventCloseWorkerThread );
    m_hEventCloseWorkerThread = NULL;
  }
  if ( m_hEventTaskArrived )
  {
    CloseHandle( m_hEventTaskArrived );
    m_hEventTaskArrived = NULL;
  }
  if ( m_hEventWaitDataReceived )
  {
    CloseHandle( m_hEventWaitDataReceived );
    m_hEventWaitDataReceived = NULL;
  }

  if ( m_hEventDataReceived )
  {
    CloseHandle( m_hEventDataReceived );
    m_hEventDataReceived = NULL;
  }
  if ( m_hEventDataWritten )
  {
    CloseHandle( m_hEventDataWritten );
    m_hEventDataWritten = NULL;
  }

  if ( m_hPort == INVALID_HANDLE_VALUE )
  {
    return;
  }

  CloseHandle( m_hPort );
  m_hPort = INVALID_HANDLE_VALUE;

  dh::Log( "close done" );

}


ResultTextIDs WaitForResult()
{

  HANDLE    hEventGroup[2];

  hEventGroup[0] = m_hEventCloseWorkerThread;
  hEventGroup[1] = m_hEventWaitDataReceived;

  while ( true )
  {
    // TODO - Timeout konfigurieren
    DWORD   dwResult = WaitForMultipleObjects( 2, hEventGroup, FALSE, m_dwResultTimeout );
    if ( dwResult == WAIT_OBJECT_0 )
    {
      // Ende
      CancelIo( m_hPort );
      SetEvent( m_hEventCloseWorkerThread );
      return RES_ABORT_DUE_SHUTDOWN;
    }
    else if ( dwResult == WAIT_OBJECT_0 + 1 )
    {
      // Daten empfangen
      ResetEvent( m_hEventWaitDataReceived );
    }
    else if ( dwResult == WAIT_TIMEOUT )
    {
      dh::Log( "WaitForResult - Timeout" );
      return RES_CONNECTION_TIMEOUT;
    }
    else
    {
      dh::Log( "WaitForResult - Result %d", dwResult );
    }
  }

  return RES_INTERNAL_ERROR;

}


// die Klassen-Eigene Thread-Run-Funktion
DWORD Run()
{ 

  // Set up overlapped structure fields.
  dh::Log( "COM Thread started" );

  m_hEventDataReceived = CreateEvent( NULL, FALSE, FALSE, NULL );

  memset( &m_ovRead, 0, sizeof( m_ovRead ) );
  m_ovRead.Offset     = 0; 
  m_ovRead.OffsetHigh = 0; 
  m_ovRead.hEvent     = m_hEventDataReceived; 

  HANDLE            hEventGroup[2];

  hEventGroup[0] = m_hEventDataReceived;
  hEventGroup[1] = m_hCloseEvent;

  unsigned char     ucLocalBuffer[2048];

  DWORD             dwLocalBytesRead;

  DWORD             dwStartTicks = 0;

  DWORD             dwLocalBufferOffset = 0;

  bool              bDataSent = false;

  CByteBuffer       bbIncoming;


  // Setup-Vorgang fortsetzen im Thread, damit der User nicht so lange warten muß
  SetDCB( 9600, 8, 0, 2 );
  // 9600,n,8,2

  if( !SetCommState( m_hPort, &m_DCB ) )
	{
    ClosePort();
    dh::Log( "SetCommState failed" );
	  return 1;
	}

  HANDLE      hEventCom = CreateEvent( NULL, TRUE, FALSE, NULL );

  OVERLAPPED    ovCom;

  memset( &ovCom, 0, sizeof( ovCom ) );
  ovCom.hEvent = hEventCom;

  // HaveToShutDown prüft, ob ShutDown für den Thread aufgerufen worden ist
  while ( !HaveToShutDown() )
  {
    DWORD   dwEventMask = 0;

    // Event an Com-Schnittstelle übergeben
    //dh::Log( "WaitCommEvent..." );
    if ( !WaitCommEvent( m_hPort, &dwEventMask, &ovCom ) )
    {
      DWORD   dwError = GetLastError();
      if ( dwError != ERROR_IO_PENDING )
      {
        //dh::Log( "WaitCommEvent error %x", GetLastError() );
        return 1;
      }
    }

    //dh::Log( "WaitCommEvent done" );
    // jetzt auf eines der beiden Events warten
    hEventGroup[0] = ovCom.hEvent;
    DWORD   dwResult = WaitForMultipleObjects( 2, hEventGroup, FALSE, INFINITE );
    //dh::Log( "WaitForMultipleObjects returned %d", dwResult );
    if ( dwResult == WAIT_OBJECT_0 + 1 )
    {
      // Ende, Close-Event wieder setzen
      dh::Log( "Close-Event" );
      SetEvent( m_hCloseEvent );
      break;
    }

    hEventGroup[0] = m_hEventDataReceived;
    int iResult = ReadFile( m_hPort, ucLocalBuffer, 512, &dwLocalBytesRead, &m_ovRead );
    //dh::Log( "ReadFile returned %d - %d Bytes read", iResult, dwLocalBytesRead );
    if ( iResult )
    {
      //dh::Log( "Received %d Bytes directly", dwLocalBytesRead );
      if ( dwLocalBytesRead )
      {
        //dh::Log( "ReadFile %d bytes read (pos2)", dwLocalBytesRead );
        EnterCriticalSection( &m_csIncomingData );
        bbIncoming.AppendData( ucLocalBuffer, dwLocalBytesRead );

        GR::u32 dwBytesUsed = ReceiveData( bbIncoming );
        bbIncoming.TruncateFront( dwBytesUsed );

        LeaveCriticalSection( &m_csIncomingData );
        // es kamen Daten an
        //dh::Log( "Received %d Bytes\n", dwLocalBytesRead );
      }
    }
    else if ( !iResult )
    {
      // Deal with the error code. 
      DWORD     dwError = GetLastError();

      switch ( dwError  ) 
      { 
        case ERROR_HANDLE_EOF: 
          { 
            // WCode to handle the end of the file 
            // during the call to ReadFile 
          } 
          break;
        case ERROR_IO_PENDING: 
          { 
            //dh::Log( "IO pending" );
            // Asynchronous I/O is still in progress
            // Check on the results of the asynchronous read. 
            DWORD   dwResult = WaitForMultipleObjects( 2, hEventGroup, FALSE, INFINITE );

            //dh::Log( "WaitForMultipleObjects returned %d", dwResult );

            if ( dwResult == WAIT_OBJECT_0 )
            {
              //dh::Log( "Data read" );
              BOOL bResult = GetOverlappedResult( m_hPort, &m_ovRead, &dwLocalBytesRead, TRUE ); 
              // If there was a problem  
              if ( !bResult ) 
              { 
                // Deal with the error code. 
                switch (dwError = GetLastError()) 
                { 
                  case ERROR_HANDLE_EOF: 
                    { 
                      // We have reached the end of
                      // the file during asynchronous
                      // operation.
                    } 
                    break;
                    // Deal with other error cases. 
                }   //end switch (dwError = GetLastError()) 
              } 
              else
              {
                if ( dwLocalBytesRead )
                {
                  //dh::Log( "ReadFile %d bytes read (pos2)", dwLocalBytesRead );
                  EnterCriticalSection( &m_csIncomingData );
                  bbIncoming.AppendData( ucLocalBuffer, dwLocalBytesRead );

                  GR::u32 dwBytesUsed = ReceiveData( bbIncoming );
                  bbIncoming.TruncateFront( dwBytesUsed );

                  LeaveCriticalSection( &m_csIncomingData );
                  // es kamen Daten an
                  //dh::Log( "Received %d Bytes\n", dwLocalBytesRead );
                }
              }
            }
            else if ( dwResult == WAIT_OBJECT_0 + 1 )
            {
              dh::Log( "Close Event set -> CancelIO" );
              CancelIo( m_hPort );
              dh::Log( "done" );

              // Event wieder setzen
              SetEvent( m_hCloseEvent );

              goto leave_loop;
              break;
            }
          }
          break;
      }
    }
  }

  leave_loop:;
  dh::Log( "COM: Left Read Thread" );

  return 0;

}



DWORD WorkerThread()
{

  dh::Log( "WorkerThread started" );
  HANDLE    hEventGroup[2];

  hEventGroup[0] = m_hEventCloseWorkerThread;
  hEventGroup[1] = m_hEventTaskArrived;

  dh::Log( "Event %x/%x", m_hCloseEvent, m_hEventTaskArrived );

  while ( true )
  {
    // TODO - auf Schliessen oder neues-Item-Event warten!
    dh::Log( "WorkerThread Wait..." );
    DWORD   dwResult = WaitForMultipleObjects( 2, hEventGroup, FALSE, INFINITE );
    dh::Log( "-done %d", dwResult );

    if ( dwResult == WAIT_OBJECT_0 )
    {
      // Ende
      dh::Log( "WorkerThread: Close Event received" );
      SetEvent( m_hEventCloseWorkerThread );
      break;
    }
    else if ( dwResult == WAIT_OBJECT_0 + 1 )
    {
      ResetEvent( m_hEventTaskArrived );

      // sind noch Tasks vorhanden, dann Event wieder setzen
      EnterCriticalSection( &m_csListAccess );
      if ( !m_listTasks.empty() )
      {
        SetEvent( m_hEventTaskArrived );
      }
      LeaveCriticalSection( &m_csListAccess );
    }
    else
    {
      dh::Log( "WorkerThread: Fehler bei WaitForMultipleObjects %d/%x", dwResult, GetLastError() );
    }
  }

  dh::Log( "Worker Thread shut down" );

  return 0;

}

Der Code ist ein bißchen durcheinandergewürftelt und es fehlen auch ein paar Schnipsel, die ich nicht so einfach zeigen kann. Das Prinzip der einzlenen Aufrufe sollte aber klar sein. Versuch einfach nicht, meinen Thread-Sauhaufen zu verstehen :)
 
Ich werde mich mal durch "wühlen" ;-)
Vielen Dank
Auf den ersten Blick habe ich das mit den Events auch so ähnlich gemacht, nun gut ich werde weiter probieren

Gruß
Ktm_Frans
 
So, habe das hinbekommen.
Habe da die Handle etwas falsch zugewiesen!
Jetzt läuft es... :-)

Vielen Dank für die Unterstützung!
 
Zurück