Thread: Expert, Help please! MultiThreading in C++

  1. #1
    Registered User
    Join Date
    May 2002
    Posts
    85

    Question Expert, Help please! MultiThreading in C++

    Dear Sir or Madam,

    I am trying to create 3 threads running paralelly in an C++ object . It is easy to create in C but it's hard and very confusing in C++ object.

    Code:
    #include <pthread.h>
    #include <unix.h>
    
    
    class ControlManager
    {
       public:
         void ReadMessage(); // This function need associated as a  
                                               //thread
         void WriteMessage();    // also a thread
         void MainLoop();            // also a thread
    
         void SpawnThreads();
    
       private:
         pthread_t   thread1,  thread2,  thread3;
      
    }
    
    void ControlManager::SpawnThreads()
    {
        pthread_create(thread1, NULL, ReadMessage, NULL);
        pthread_create(thread2, NULL, WriteMessage, NULL);
        pthread_create(thread3, NULL, MainLoop, NULL);
    }
    Any experts out here can help or point me a right direction.

    I greatly appreciated .

  2. #2
    Registered User
    Join Date
    Aug 2002
    Location
    Hermosa Beach, CA
    Posts
    446
    The problem is that the functions that you pass as the start method are member functions of a class, and so they require a this pointer to be implicitly passed. One simple solution is to make the methods static member functions, or another solution is make them non-member functions. Another more complicated method is to make functors that store the this pointer as pThis, and then in operator() you call pThis->ReadMessage() for instance. That way if you need the class instance you have it. Or you could call a non-member function and for thread data you pass this, and then in your thread start function you just cast this pointer to the appropriate type, and call this->ReadData(). Many choices...
    The crows maintain that a single crow could destroy the heavens. Doubtless this is so. But it proves nothing against the heavens, for the heavens signify simply: the impossibility of crows.

  3. #3
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    So what's the problem ?
    Guess the function prototypes don't match.
    Use static methods.
    Kurt

  4. #4
    Registered User
    Join Date
    May 2002
    Posts
    85
    Quote Originally Posted by IfYouSaySo
    The problem is that the functions that you pass as the start method are member functions of a class, and so they require a this pointer to be implicitly passed. One simple solution is to make the methods static member functions, or another solution is make them non-member functions. Another more complicated method is to make functors that store the this pointer as pThis, and then in operator() you call pThis->ReadMessage() for instance. That way if you need the class instance you have it. Or you could call a non-member function and for thread data you pass this, and then in your thread start function you just cast this pointer to the appropriate type, and call this->ReadData(). Many choices...
    Thanx for your attention.

    Would you mind to show a specific example how to code them.
    Using wrapper in C++ kinda confusing, especially when creating multi threads within an object. An object can have many threads running parallelly handle different services. Which of your comments above are most effecicent and less overhead ?
    Again, thank you very much for your help and expertise.

  5. #5
    Registered User
    Join Date
    Aug 2002
    Location
    Hermosa Beach, CA
    Posts
    446
    Well...take your pick between the methods. They all amount to the same I think. Depends on what you need. I'll show each method and give the pros and cons as I see it. By the way, I'm just rattling this code off the top of my head, so some might have minor compile errors. I changed the prototypes for the functions...I think that is the right prototype for pthread functions. Definately need to pass a void* param as data to the thread. Pretty sure that it returns an int. Try "man pthread_create" to double check the prototype.

    Also, you'll need to sort out the issues with prototypes here for example 4. The compiler is going to complain because MainLoop references ControlManager before ControlManager is defined. If you don't know how to fix this with header files, then just skip example 4.

    Method 1: Make the member functions static.
    Pros: Easy to implement.
    Cons: You don't have an instance of the object to work with. For example purposes, I added a member data "int member_data" for example purposes.

    Code:
    #include <pthread.h>
    #include <unix.h>
    
    
    class ControlManager
    {
       public:
        int member_data;
         static int ReadMessage(void* data); // This function need associated as a  
                                               //thread
         static int WriteMessage(void* data);    // also a thread
         static int MainLoop(void* data);            // also a thread
    
         void SpawnThreads();
    
       private:
         pthread_t   thread1,  thread2,  thread3;
      
    }
    
    void ControlManager::SpawnThreads()
    {
        pthread_create(thread1, NULL, ReadMessage, NULL);
        pthread_create(thread2, NULL, WriteMessage, NULL);
        pthread_create(thread3, NULL, MainLoop, NULL);
    }
    
    int ControlManager::ReadMessage(void* data)
    {
        // data can be anything you want, passed in from the pthread_create call.
        // We don't use it here
    
        // This won't work!! You don't really have a this pointer, and that is the real drawback
        // this->member_data = 10;
    }
    Method 2: Non-member functions
    Pros: Easy like first solution
    Cons: Again, you don't have a this pointer

    Code:
    #include <pthread.h>
    #include <unix.h>
    
    /* Non-member functions */
    int ReadMessage(void* data)
    {
    
    }
    
    int WriteData(void* data)
    {
    
    }
    
    int MainLoop(void* data)
    {
    
    }
    
    class ControlManager
    {
       public:
        int member_data;
    
         void SpawnThreads();
    
       private:
         pthread_t   thread1,  thread2,  thread3;
      
    }
    
    void ControlManager::SpawnThreads()
    {
        pthread_create(thread1, NULL, ReadMessage, NULL);
        pthread_create(thread2, NULL, WriteMessage, NULL);
        pthread_create(thread3, NULL, MainLoop, NULL);
    }
    Method 3: Same as method 2, but pass pointer to object as parameter to pthread_create
    Pros: This poniter available
    Cons: No idea

    Code:
    #include <pthread.h>
    #include <unix.h>
    
    /* Prototypes */
    int ReadData(void* data);
    int WriteData(void* data);
    int MainLoop(void* data);
    
    class ControlManager
    {
       public:
        int member_data;
    
         void SpawnThreads();
    
       private:
         pthread_t   thread1,  thread2,  thread3;
      
    }
    
    void ControlManager::SpawnThreads()
    {
        pthread_create(thread1, NULL, ReadMessage, this);
        pthread_create(thread2, NULL, WriteMessage, this);
        pthread_create(thread3, NULL, MainLoop, this);
    }
    
    /* Non-member functions */
    int ReadMessage(void* data)
    {
        ControlManager* pThis = (ControlManager *)data;
    
        // works now
        pThis->member_data = 10;
    }
    
    int WriteData(void* data)
    {
        ControlManager* pThis = (ControlManager *)data;
    
        // works now
        pThis->member_data = 10;
    }
    
    int MainLoop(void* data)
    {
        ControlManager* pThis = (ControlManager *)data;
    
        // works now
        pThis->member_data = 10;
    }
    Fourth Method: Use functors
    Pros: This pointer available, your friends think you're cool
    Cons: More compilcated; someone might ask you to explain it

    Code:
    #include <pthread.h>
    #include <unix.h>
    
    /* Functors: */
    
    class ReadData {
        private:
        ControlManager* pThis;
    
        public:
    
        ReadData(ControlManager* p) { pThis = p; }
    
        int operator()(void* data) 
        {
            pThis->member_data = 100;
        }
    };
    
    class WriteData {
        private:
        ControlManager* pThis;
    
        public:
    
        WriteData(ControlManager* p) { pThis = p; }
    
        int operator()(void* data) 
        {
            pThis->member_data = 100;
        }
    };
    
    class MainLoop {
        private:
        ControlManager* pThis;
    
        public:
    
        MainLoop(ControlManager* p) { pThis = p; }
    
        int operator()(void* data) 
        {
            pThis->member_data = 100;
        }
    };
    
    class ControlManager
    {
       public:
        int member_data;
    
         void SpawnThreads();
    
       private:
         pthread_t   thread1,  thread2,  thread3;
      
    }
    
    void ControlManager::SpawnThreads()
    {
        pthread_create(thread1, NULL, ReadMessage(this), NULL);
        pthread_create(thread2, NULL, WriteMessage(this),NULL);
        pthread_create(thread3, NULL, MainLoop(this), NULL);
    }
    The crows maintain that a single crow could destroy the heavens. Doubtless this is so. But it proves nothing against the heavens, for the heavens signify simply: the impossibility of crows.

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    You could just use Boost.Threads.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #7
    the hat of redundancy hat nvoigt's Avatar
    Join Date
    Aug 2001
    Location
    Hannover, Germany
    Posts
    3,130
    I like all my code in one class, though any of the above methods will work...

    PHP Code:
    #include <pthread.h>
    #include <unix.h>


    class ControlManager
    {
    public:
         
    void SpawnThreads();

    // If you need any of these methods to be public, you probably have a conceptional oversight in your class layout
    // SpawnThreads spawns the threads. If it doesn't, redo your class layout or code. 
    private:
         
    void ReadMessage();     // This function need associated as a thread
         
    void WriteMessage();        // also a thread
         
    void MainLoop();           // also a thread

         
    static void ReadMessageStartervoid* );
         static 
    void WriteMessageStartervoid* );
         static 
    void MainLoopStartervoid* );

    private:
         
    pthread_t thread1thread2thread3;
      
    };

    void ControlManager::SpawnThreads()
    {
        
    pthread_create(thread1NULLReadMessageStarterthis );
        
    pthread_create(thread2NULLWriteMessageStarterthis );
        
    pthread_create(thread3NULLMainLoopStarterthis );
    }

    void ControlManager::ReadMessage()
    {
        
    // your thread, access to this, make sure to sync access to data
    }

    void ControlManager::WriteMessage()
    {
        
    // your thread, access to this, make sure to sync access to data
    }

    void ControlManager::MainLoop()
    {
        
    // your thread, access to this, make sure to sync access to data
    }

    void ControlManager::ReadMessageStartervoid)
    {
        
    ControlManagerpThis = (ControlManager*)p;

        
    pThis->ReadMessage();
    }

    void ControlManager::WriteMessageStartervoid)
    {
        
    ControlManagerpThis = (ControlManager*)p;

        
    pThis->WriteMessage();
    }

    void ControlManager::MainLoopStartervoid)
    {
        
    ControlManagerpThis = (ControlManager*)p;

        
    pThis->MainLoop();

    hth
    -nv

    She was so Blonde, she spent 20 minutes looking at the orange juice can because it said "Concentrate."

    When in doubt, read the FAQ.
    Then ask a smart question.

  8. #8
    Registered User major_small's Avatar
    Join Date
    May 2003
    Posts
    2,787
    maybe slightly off-topic, but can anybody give me any working examples of code using boost::threads? I keep comming across the same example in searches, and fixes for that broken example, but even with all different kinds of fixes people have suggested, I still can't seem to get it to work...
    Join is in our Unofficial Cprog IRC channel
    Server: irc.phoenixradio.org
    Channel: #Tech


    Team Cprog Folding@Home: Team #43476
    Download it Here
    Detailed Stats Here
    More Detailed Stats
    52 Members so far, are YOU a member?
    Current team score: 1223226 (ranked 374 of 45152)

    The CBoard team is doing better than 99.16% of the other teams
    Top 5 Members: Xterria(518175), pianorain(118517), Bennet(64957), JaWiB(55610), alphaoide(44374)

    Last Updated on: Wed, 30 Aug, 2006 @ 2:30 PM EDT

  9. #9
    Registered User
    Join Date
    May 2002
    Posts
    85
    Thank you all for your help.

    nvoigt,

    Since you typecast 3 times (entry point for each thread) as:
    Code:
     ControlManager* pThis = (ControlManager*)p;
    Does it mean it creates three pointers point to the same object ControlManager? My concern is also about overhead .

    pthis---------> ControlManager
    pthis---------> ControlManager
    pthis---------> ControlManager

    is it three pointers or one pointer point to ControlManager object ?
    Last edited by dv007; 01-07-2006 at 02:05 PM.

  10. #10
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Since you typecast 3 times (entry point for each thread) as:
    Code:
    ControlManager* pThis = (ControlManager*)p;
    Does it mean it creates three pointers point to the same object ControlManager?
    Yes, it does.
    My concern is also about overhead .
    That would be very insignificant. But if you're really concerned about it you could cast the variable every time you use it:
    Code:
    void ControlManager::MainLoopStarter( void* p ) 
    { 
        ControlManager* pThis = (ControlManager*)p; 
    
        pThis->MainLoop(); 
    }
    ->
    Code:
    void ControlManager::MainLoopStarter( void* p )
    {
        ((ControlManager*)p)->MainLoop();
    }
    Or maybe pass a variable of type ControlManager* instead of void*.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  11. #11
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    Quote Originally Posted by dv007
    Does it mean it creates three pointers point to the same object ControlManager? My concern is also about overhead.
    Don't worry the cast doesn't produce any code. If its the local variable you don't like you could do it this way

    Code:
    void ControlManager::MainLoopStarter( void* p ) {
        ((ControlManager*)p)->MainLoop();
    }
    Kurt

    Edit:Too late
    Last edited by ZuK; 01-07-2006 at 02:12 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Multithreading (flag stopping a thread, ring buffer) volatile
    By ShwangShwing in forum C Programming
    Replies: 3
    Last Post: 05-19-2009, 07:27 AM
  2. Question on Multithreading
    By ronan_40060 in forum C Programming
    Replies: 1
    Last Post: 08-23-2006, 07:58 AM
  3. Multithreading
    By JaWiB in forum Game Programming
    Replies: 7
    Last Post: 08-24-2003, 09:28 PM
  4. Expert system?
    By FloatingPoint in forum Tech Board
    Replies: 1
    Last Post: 06-14-2003, 07:23 AM
  5. c++ expert
    By febrian81 in forum C++ Programming
    Replies: 2
    Last Post: 07-01-2002, 10:27 PM