Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 13110
  • Last Modified:

Windows multithreading C++ help

I have written multithreaded code under Linux several times with successful outcomes...but I have to admit that Windows has got me beat. I have read loads of online tutorials and book examples...but can get none to work.

All I need is to create a thread which goes off on its merry way altering a global array. It needs no intervention or control...just creating. Please can somebody just give me some code which I can cut and paste into MFC and change the controlling method body to do what I need to it to. Please. I beg of you.

yours, one completely depressed Linux developer who is forced into Windows development. =)
0
dewils80
Asked:
dewils80
  • 8
  • 4
  • 2
  • +4
2 Solutions
 
AlexFMCommented:
Check out MFC sample MTRECALC.
0
 
havman56Commented:
simplest code which prints facxe on the screen threads created by pressinga key.

0
 
havman56Commented:




/*
*included files for multithreading
*/
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <process.h>
#include< iostream.h>
#define MAX_THREADS  32

/*
* getrandom returns a random number between min and max, which must be in
* integer range.
*/
#define getrandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))

class Thread
{
public:                                /* Thread 1: main */
void KbdFunc( void  );                 /* Keyboard input, thread dispatch */
void ClearScreen( void );              /* Screen clear */
void ShutDown( void );                 /* Program shutdown */
void WriteTitle( int ThreadNum );
void begin();
void end();                            /* Display title bar information */

private:
int     ThreadNr;                      /* Number of threads started */

};

void BounceProc( void *MyID );
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
HANDLE  hConsoleOut;                   /* Handle to the console */
HANDLE  hRunMutex;                     /* "Keep Running" mutex */
HANDLE  hScreenMutex;


/*******************************************************************
* Function Name          : begin ()
* Return Values          : none
* Global variables      : None
* Description               : create mutex
********************************************************************/

void Thread::begin()
{
 hConsoleOut = GetStdHandle( STD_OUTPUT_HANDLE );
   GetConsoleScreenBufferInfo( hConsoleOut, &csbiInfo );
   ClearScreen();
   WriteTitle( 0 );
   /*
    * Create the mutexes and reset thread count.
      */
   hScreenMutex = CreateMutex( NULL, FALSE, NULL );   /* Cleared */
   hRunMutex = CreateMutex( NULL, TRUE, NULL );       /* Set */
   ThreadNr = 0;
}

/*******************************************************************
* Function Name          : end ()
* Return Values          : none
* Global variables      : None
* Description               : delete the mutex
********************************************************************/


void Thread::end()
{
   CloseHandle( hScreenMutex );
   CloseHandle( hRunMutex );
   CloseHandle( hConsoleOut );
};


/*******************************************************************
* Function Name          : main ()
* Return Values          : none
* Global variables      : None
* Description               : start and end function call
********************************************************************/

void main()                            
{
     Thread t;
   /* Get display screen information & clear the screen.*/
   t.begin();
   /*
      * Start waiting for keyboard input to dispatch threads or exit.
      */
   t.KbdFunc();
   t.end();
   /* All threads done. Clean up handles. */
   
}

/*******************************************************************
* Function Name          : shutdown ()
* Return Values          : none
* Global variables      : None
* Description               : release mutex
********************************************************************/

void Thread:: ShutDown( void )                  /* Shut down threads */
{
   while ( ThreadNr > 0 )
   {
         /*
             * Tell thread to die and record its death.
             */
           ReleaseMutex( hRunMutex );
           ThreadNr--;  
   }
   /*
      * Clean up display when done
      */
   WaitForSingleObject( hScreenMutex, INFINITE );
   ClearScreen();
}

/*******************************************************************
* Function Name          : kbdfunc()
* Return Values          : none
* Global variables      : None
* Description               : detect the key press and begin thread for
*                                each key press
********************************************************************/

void Thread::KbdFunc( void )                  
{
     
   int         KeyInfo;

   do
   {
       KeyInfo = _getch();
       if( tolower( KeyInfo ) == 'a' && ThreadNr < MAX_THREADS )
       {
           ThreadNr++;

           _beginthread(BounceProc, 0, &ThreadNr );
               if (ThreadNr==2)
           WriteTitle( ThreadNr );
       }
   } while( tolower( KeyInfo ) != 'q' );

   ShutDown();
}

/*******************************************************************
* Function Name          : bounceproc ()
* Return Values          : none
* Global variables      : None
* Description               : This is the thread entry function when thread is created
*                        calls this function . so each thread should obtain
*                        the mutex and draw its face .afetr drawing its
*                                face release the mutex so next thread can draw
********************************************************************/


void BounceProc( void *MyID )
{



char *MyNum=(char *)MyID;

   char      MyCell, OldCell;
   WORD      MyAttrib, OldAttrib;
   char      BlankCell = 0x20;
   COORD     Coords, Delta;
   COORD     Old = {0,0};
   DWORD     Dummy;

  /*
     * Generate update increments and initial display coordinates.
     */
   srand( (unsigned  )   *MyNum * 3 );
   Coords.X = getrandom( 0, csbiInfo.dwSize.X - 1 );
   Coords.Y = getrandom( 0, csbiInfo.dwSize.Y - 1 );
   Delta.X = getrandom( -3, 3 );
   Delta.Y = getrandom( -3, 3 );

   /*
      * Set up "happy face" & generate color attribute from thread number.
      */
   if( *MyNum> 16)
       MyCell = 0x01;                 /* outline face */
   else
       MyCell = 0x02;                 /* solid face */
   MyAttrib =  *MyNum & 0x0F;          /* force black background */

   do
   {
       /*
            * Wait for display to be available, then lock it.
           */
       WaitForSingleObject( hScreenMutex, INFINITE );

       /*
           * If we still occupy the old screen position, blank it out.
            */
       ReadConsoleOutputCharacter( hConsoleOut, &OldCell, 1, Old, &Dummy );
       ReadConsoleOutputAttribute( hConsoleOut, &OldAttrib, 1, Old, &Dummy );
       if (( OldCell == MyCell ) && (OldAttrib == MyAttrib))
           WriteConsoleOutputCharacter( hConsoleOut, &BlankCell, 1, Old, &Dummy );

       /*
           * Draw new face, then clear screen lock
           */
       WriteConsoleOutputCharacter( hConsoleOut, &MyCell, 1, Coords, &Dummy );
       WriteConsoleOutputAttribute( hConsoleOut, &MyAttrib, 1, Coords, &Dummy );
       ReleaseMutex( hScreenMutex );

       /*
           *Increment the coordinates for next placement of the block.
           */
       Old.X = Coords.X;
       Old.Y = Coords.Y;
       Coords.X += Delta.X;
       Coords.Y += Delta.Y;

       /*
           * If we are about to go off the screen, reverse direction
           */
       if( Coords.X < 0 || Coords.X >= csbiInfo.dwSize.X )
       {
           Delta.X = -Delta.X;
           Beep( 400, 50 );
       }
       if( Coords.Y < 0 || Coords.Y > csbiInfo.dwSize.Y )
       {
           Delta.Y = -Delta.Y;
           Beep( 600, 50 );
       }


   }

   /* Repeat while RunMutex is still taken. */
   while ( WaitForSingleObject( hRunMutex, 75L ) == WAIT_TIMEOUT );

}

/*******************************************************************
* Function Name          : write title ()
* Return Values          : none
* Global variables      : None
* Description               : writes title in title bar
********************************************************************/

void Thread ::WriteTitle( int ThreadNum )
{
   char    NThreadMsg[80];

   sprintf( NThreadMsg, "Threads running: %02d.  Press 'A' to start a thread,'Q' to quit.", ThreadNum );
   SetConsoleTitle( NThreadMsg );
}

/*******************************************************************
* Function Name          : clearscreen ()
* Return Values          : none
* Global variables      : None
* Description               : clear the screen  
********************************************************************/

void Thread::ClearScreen( void )
{
   DWORD    dummy;
   COORD    Home = { 0, 0 };
   FillConsoleOutputCharacter( hConsoleOut, ' ', csbiInfo.dwSize.X * csbiInfo.dwSize.Y, Home, &dummy );
}

 
0
Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

 
jhanceCommented:
Not really a C++ topic area question.  This is a Windows Programming question.  You'll get better response to this from experts in the correct topic area.
0
 
jkrCommented:
0
 
komarCommented:
Below is a simple form of a thread created using MFC.
MFC calls this thread a Worker Thread.

      //Define thread procedure
      UINT ThreadProc(LPVOID pParam)
      {
            UINT uExitCode = 0;
            ...
            ...//Do something
            ...
            return uExitCode;
      }

      //Create thread
      CWinThread *pThread = NULL;
      HANDLE hThread = NULL;
      
      pThread = AfxBeginThread(ThreadProc, NULL, THREAD_PRIORITY_NORMAL, 0, 0, NULL);
      hThread = pThread ? NULL : pThread->hThread;

NOTE: If for any reason you want to wait for the thread to finish it's job then you have to write the following:
      //Wait for thread to finish
      if(hThread)
      {
            WaitForSingleObject(hThread, INFINITE);
            //Thread terminated and will auto destruct itself (no need to do delete pThread)
      }

Thanks,
Khalid Omar.
0
 
komarCommented:
Oops, I forgot to close the handle optained from pThread->m_hThread in the last section of my comment above. So, the modified code should look like:

     //Wait for thread to finish
     if(hThread)
     {
          WaitForSingleObject(hThread, INFINITE);
          //Thread terminated and will auto destruct itself (no need to do delete pThread)

          CloseHandle(hThread);
     }

Thanks,
Khalid.
0
 
komarCommented:
Damn, seems I'm very sleepy; I keep making mistakes!

Here is a list of mistakes that I made in my first  and second comments:
  - CWinThread does not have a member variable called hThread, but it has m_hThread instead.
  - CloseHandle() is not required becasue the destructor does the job when called via auto-destruction of the thread object.
  - In the above conditional statement (? :) I reversed the order of the expressions.

So, here is all the code repeated but without mistakes (hopefully :-D)

      //Define thread procedure
      UINT ThreadProc(LPVOID pParam)
      {
            UINT uExitCode = 0;
            
            ...
            ...//Do something
            ...
            
            return uExitCode;
      }

      //Create thread
      CWinThread *pThread = AfxBeginThread(ThreadProc, NULL, THREAD_PRIORITY_NORMAL, 0, 0, NULL);

NOTE: If for any reason you want to wait for the thread to finish it's job then you have to write the following:
      //Wait for thread to finish
      if(pThread)
      {
            WaitForSingleObject(pThread->m_hThread, INFINITE);
            //Thread terminated and will auto destruct itself (no need to do delete pThread)
      }
Thanks,
Khalid Omar.
0
 
dewils80Author Commented:
I have these errors returned:

d:\sr3\network management\eventhandler\cbellhandler.h(37) : error C2146: syntax error : missing ';' before identifier 'ThreadProc'
d:\sr3\network management\eventhandler\cbellhandler.h(37) : error C2501: 'UINT' : missing storage-class or type specifiers
d:\sr3\network management\eventhandler\cbellhandler.h(37) : error C2061: syntax error : identifier 'LPVOID'
d:\sr3\network management\eventhandler\cbellhandler.cpp(36) : error C2511: 'ThreadProc' : overloaded member function 'unsigned int (void *)' not found in 'CBellHandler'
        d:\sr3\network management\eventhandler\cbellhandler.h(32) : see declaration of 'CBellHandler'
d:\sr3\network management\eventhandler\cbellhandler.cpp(64) : error C2065: 'CWinThread' : undeclared identifier
d:\sr3\network management\eventhandler\cbellhandler.cpp(64) : error C2065: 'pThread' : undeclared identifier
d:\sr3\network management\eventhandler\cbellhandler.cpp(64) : error C2065: 'AfxBeginThread' : undeclared identifier
d:\sr3\network management\eventhandler\cbellhandler.cpp(64) : error C2106: '=' : left operand must be l-value

0
 
dewils80Author Commented:
This is my header file:

#pragma warning(disable: 4786)
#include "stdafx.h"
#include <cstdio>
#include <iostream>
#include <fstream>
#include <list>
#include <string>
#include <algorithm>
#include <OV/OVsnmp.h>
#include "getopt.h"            
using namespace std;

class CListHandler{
public:
    //list of constructors
      int IsAtUUI(char* UUItoLocate);
      int AddUUI(char* UUItoAdd);
      int RemUUI(char* UUItoRem);
      bool IsEmpty();
      void PrintList();

};
0
 
dewils80Author Commented:
sorry, wrong one....this is the header file:

// Prevent Warning "identifier was truncated to 255 characters in debug information"
#pragma warning(disable: 4786)
#include "stdafx.h"
#include <cstdio>
#include <iostream>
#include <fstream>
#include <list>
#include <string>
#include <algorithm>
#include <stdio.h>
using namespace std;


class CBellHandler{

      public:
            //list of constructors
            void BellHandler();
            UINT ThreadProc(LPVOID);
            
};
0
 
dewils80Author Commented:
and this is the CPP:

#include "stdafx.h"
      #include "CBellHandler.h"
      #include "CListHandler.h"
CListHandler ListHandler;

      #include <stdio.h>
      #include <stdlib.h>
      #include <errno.h>
      #undef _CLASSIC_ANSI_TYPES        /* get function prototype for strlen() */
      #include <string.h>
      #include <sys/types.h>
      #include <windows.h>            /* For Win32 Message Loop            */
      #include <time.h>

UINT CBellHandler::ThreadProc(LPVOID pParam) {

      int Diff = 0;      //Holds the difference in secs between sys times
      time_t last_systime;      //Time variables to capture the system time
      time_t current_systime;
      UINT exitcode = 0;

      time (&current_systime);      //Initialise time variables
      time (&last_systime);

      while(true){      //loop forever
            Diff = difftime(current_systime, last_systime);
            if(0 != (ListHandler.IsEmpty)){      //If there is something in the alert list
                  if(Diff > 5.00){                  //If it is at least 5 secs since last beep
                        EventProcessing.generateBeep();      //Generate a beep
                        time (&last_systime);      //Update the time last beep generated.
                  }
            }
      }

      return exitcode;

}

void CBellHandler::BellHandler(void){

      HANDLE bell_threadHandle;
      DWORD bell_threadID;
      CWinThread *pThread = AfxBeginThread(ThreadProc, NULL, THREAD_PRIORITY_NORMAL,0,0,NULL);

      //bell_threadHandle = CreateThread(NULL, NULL,(LPTHREAD_START_ROUTINE) BellGenerate, NULL, 0, &bell_threadID);



}

0
 
komarCommented:
I thought you said (>> .. which I can cut and paste into MFC and change the controlling method  ..) which means your project is using MFC!
According to the header/cpp files you have then your project does not use MFC, that is why you received so many errors during compilation.

If you decide to convert your project to MFC then make sure to update the ThreadProc() method signature to the following:

     static UINT ThreadProc(LPVOID);

This is because the CreateThread() only accepts global or static class methods in it's third parameter.
0
 
dewils80Author Commented:
Sorry, I typed MFC when I meant MSVC....

I cannot convert the project to MFC because this is a tiny part of a huge application.

Anyone able to help?
0
 
dewils80Author Commented:
Points being increased to try and get response.
0
 
jrocnuckCommented:
use the Win32 thread functions

_beginthread
_beginthreadex

this webpage has a lot to offer as far as sample code:
http://www.codeproject.com/threads/

just try to avoid the MFC topics.
0
 
jrocnuckCommented:
here is a good C++ class wrapper and demo project that doesn't use MFC

http://www.codeproject.com/threads/SynchronizedThreadNoMfc.asp
0
 
jkrCommented:
*Cough* - did you bother to look at the MSDN article I pointed out yesterday?
0
 
dewils80Author Commented:
-----------^

Yes, I had already read this article. I still have problems with it all.

Trying the latest posted suggestions.
0
 
dewils80Author Commented:
Thanks to the above sites, I have got my code to compile and run. Thanks for all the help.
0

Featured Post

Windows Server 2016: All you need to know

Learn about Hyper-V features that increase functionality and usability of Microsoft Windows Server 2016. Also, throughout this eBook, you’ll find some basic PowerShell examples that will help you leverage the scripts in your environments!

  • 8
  • 4
  • 2
  • +4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now