Solved

Windows multithreading C++ help

Posted on 2003-11-10
21
13,077 Views
Last Modified: 2013-12-03
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
Comment
Question by:dewils80
  • 8
  • 4
  • 2
  • +4
21 Comments
 
LVL 48

Expert Comment

by:AlexFM
ID: 9714769
Check out MFC sample MTRECALC.
0
 
LVL 4

Expert Comment

by:havman56
ID: 9714882
simplest code which prints facxe on the screen threads created by pressinga key.

0
 
LVL 4

Expert Comment

by:havman56
ID: 9714886




/*
*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
 
LVL 32

Expert Comment

by:jhance
ID: 9714966
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
 
LVL 86

Expert Comment

by:jkr
ID: 9716276
0
 
LVL 3

Expert Comment

by:komar
ID: 9716749
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
 
LVL 3

Expert Comment

by:komar
ID: 9716770
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
 
LVL 3

Expert Comment

by:komar
ID: 9716862
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
 

Author Comment

by:dewils80
ID: 9720775
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
 

Author Comment

by:dewils80
ID: 9720778
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
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 

Author Comment

by:dewils80
ID: 9720783
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
 

Author Comment

by:dewils80
ID: 9720785
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
 
LVL 3

Expert Comment

by:komar
ID: 9721154
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
 

Author Comment

by:dewils80
ID: 9721514
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
 

Author Comment

by:dewils80
ID: 9723336
Points being increased to try and get response.
0
 
LVL 5

Assisted Solution

by:jrocnuck
jrocnuck earned 100 total points
ID: 9725774
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
 
LVL 5

Accepted Solution

by:
jrocnuck earned 100 total points
ID: 9725802
here is a good C++ class wrapper and demo project that doesn't use MFC

http://www.codeproject.com/threads/SynchronizedThreadNoMfc.asp
0
 
LVL 86

Expert Comment

by:jkr
ID: 9725823
*Cough* - did you bother to look at the MSDN article I pointed out yesterday?
0
 

Author Comment

by:dewils80
ID: 9729709
-----------^

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

Trying the latest posted suggestions.
0
 

Author Comment

by:dewils80
ID: 9730459
Thanks to the above sites, I have got my code to compile and run. Thanks for all the help.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

If you have ever found yourself doing a repetitive action with the mouse and keyboard, and if you have even a little programming experience, there is a good chance that you can use a text editor to whip together a sort of macro to automate the proce…
As more and more people are shifting to the latest .Net frameworks, the windows presentation framework is gaining importance by the day. Many people are now turning to WPF controls to provide a rich user experience. I have been using WPF controls fo…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now