Thread: _beginthreadex and class

  1. #1
    * Death to Visual Basic * Devil Panther's Avatar
    Join Date
    Aug 2001
    Posts
    768

    _beginthreadex and class

    I'm trying to place the function that calls _beginthreadex and the the thread function under the same class, but I get a compilation error:
    error C2276: '&' : illegal operation on bound member function expression
    Code:
    class ScanAction {
    public:
       void ScanDir(char *root);
    private:
       unsigned __stdcall LyricsThread(void *params);
    };
    
    unsigned __stdcall ScanAction::LyricsThread(void *params)
    {
       ...
    }
    
    void ScanAction::ScanDir(char *root)
    {
       ...
    
       _beginthreadex(NULL, 0, &LyricsThread, NULL, 0, &dwChildId);
    
       ...
    }
    The marked part in the code is the part giving me hard time, any idea why?
    Please note what the LyricsThread function is outside the class everything works just fine.

    Thank you.
    Last edited by Devil Panther; 05-30-2007 at 03:57 PM.
    "I don't suffer from insanity but enjoy every minute of it" - Edgar Allen Poe

    http://www.Bloodware.net - Developing free software for the community.

  2. #2
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    unsigned long _beginthreadex( void *security, unsigned stack_size, unsigned ( __stdcall *start_address )( void * ), void *arglist, unsigned initflag, unsigned *thrdaddr );

    Your function LyricsThread, shoudl return type void, not unsigned __stdcall

    yeah its a bit obfuscated, which is why I prefer CreateThread();
    Last edited by abachler; 05-30-2007 at 03:54 PM.

  3. #3
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    Not that I think it will change anything, but have you tried it without the address-of? In C (and C++ I think) supplying the name of a function automatically implies its address.

  4. #4
    * Death to Visual Basic * Devil Panther's Avatar
    Join Date
    Aug 2001
    Posts
    768
    Quote Originally Posted by @nthony View Post
    Not that I think it will change anything, but have you tried it without the address-of? In C (and C++ I think) supplying the name of a function automatically implies its address.
    Yes I've trying many different combinations, nothing...
    "I don't suffer from insanity but enjoy every minute of it" - Edgar Allen Poe

    http://www.Bloodware.net - Developing free software for the community.

  5. #5
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    sorry, accidentalyl hit post instead of preview, so maybe you missed what I said. But try @nthony's suggestion first, i completely missed that you were using &LyricsThread instead of just the function name.

    Code:
    class ScanAction {
    public:
       void ScanDir(char *root);
    private:
       DWORD WINAPI LyricsThread(LPVOID params);
    };
    
    DWORD WINAPI ScanAction::LyricsThread(LPVOID params)
    {
       ...
    }
    
    void ScanAction::ScanDir(char *root)
    {
       ...
    
       CreateThread(NULL , 0 , LyricsThread , &params , 0 , &dwChildId);
       ...
    }
    Last edited by abachler; 05-30-2007 at 04:04 PM.

  6. #6
    * Death to Visual Basic * Devil Panther's Avatar
    Join Date
    Aug 2001
    Posts
    768
    Quote Originally Posted by abachler View Post
    sorry, accidentalyl hit post instead of preview, so maybe you missed what I said. But try @nthony's suggestion first, i completely missed that you were using &LyricsThread instead of just the function name.
    LyricsThread is the fucntion name, also when I use &LyricsThread and the LyricsThread is defined outside the class everything works fine.

    EDIT:
    I've found the following MSDN page that refers to that Error message: http://msdn2.microsoft.com/en-us/lib...w1(vs.80).aspx, and according this MSDN page it should be &ScanAction::LyricsThread, but this gives me the following error:
    error C2664: '_beginthreadex' : cannot convert parameter 3 from 'unsigned int (__stdcall ScanAction::* )(void *)' to 'unsigned int (__stdcall *)(void *)'
    I've also found a reply to a similar question: http://www.freelists.org/archives/pr.../msg00006.html
    But I'm some trouble understanding the solution, can anyone please help with it?
    Last edited by Devil Panther; 05-30-2007 at 04:30 PM. Reason: additional info
    "I don't suffer from insanity but enjoy every minute of it" - Edgar Allen Poe

    http://www.Bloodware.net - Developing free software for the community.

  7. #7
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    I think what MSDN is implying is that you use the Scoping operator to access the member function (instead of through regular member access).
    I.E. to pass a pointer to LyricsThread, MSDN advices you use one of these
    Code:
    &ScanAction::LyricsThread
    ScanAction::LyricsThread
    instead of any of these:
    Code:
    &LyricsThread
    LyricsThread
    &ScanAction.LyricsThread
    ScanAction.LyricsThread

  8. #8
    the hat of redundancy hat nvoigt's Avatar
    Join Date
    Aug 2001
    Location
    Hannover, Germany
    Posts
    3,130
    You cannot pass a member function to CreateThread. The function you pass must be either a function, not a class method, or it has to be static. You can create a static helper function and pass your instance, so that helper can call your class method on your instance, but then you wasted your only parameter on "this" and you have to use a member variable to actually pass anything meaningful to your thread:

    Code:
    class ScanAction {
    public:
       void ScanDir(char *root);
    private:
       LPVOID m_pThreadParams;
       static DWORD WINAPI RunLyricsThread(LPVOID params);
       DWORD WINAPI LyricsThread(LPVOID params);
    };
    
    DWORD WINAPI ScanAction::RunLyricsThread(LPVOID params)
    {
    	return ((ScanAction*)params)->LyricsThread( m_pThreadParams );
    }
    
    DWORD WINAPI ScanAction::LyricsThread(LPVOID params)
    {
       ...
    }
    
    void ScanAction::ScanDir(char *root)
    {
       ...
    
       m_pThreadParams = params; 
    
       CreateThread(NULL , 0 , RunLyricsThread, this, 0 , &dwChildId);
       ...
    }
    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.

  9. #9
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    The problem in this code can be in the point that the m_pThreadParams can be changed before its value is passed to LyricsThread function...

    for example if the block
    Code:
    m_pThreadParams = params; 
    
       CreateThread(NULL , 0 , RunLyricsThread, this, 0 , &dwChildId);
    is executed in the loop the next iteration of the loop in the main thread can be started even before the thread created with the CreateThread is resumed...
    In this case the value passed to the LyricsThread will be wrong...
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  10. #10
    * Death to Visual Basic * Devil Panther's Avatar
    Join Date
    Aug 2001
    Posts
    768
    Quote Originally Posted by nvoigt View Post
    You cannot pass a member function to CreateThread. The function you pass must be either a function, not a class method, or it has to be static. You can create a static helper function and pass your instance, so that helper can call your class method on your instance, but then you wasted your only parameter on "this" and you have to use a member variable to actually pass anything meaningful to your thread:

    Code:
    class ScanAction {
    public:
       void ScanDir(char *root);
    private:
       LPVOID m_pThreadParams;
       static DWORD WINAPI RunLyricsThread(LPVOID params);
       DWORD WINAPI LyricsThread(LPVOID params);
    };
    
    DWORD WINAPI ScanAction::RunLyricsThread(LPVOID params)
    {
    	return ((ScanAction*)params)->LyricsThread( m_pThreadParams );
    }
    
    DWORD WINAPI ScanAction::LyricsThread(LPVOID params)
    {
       ...
    }
    
    void ScanAction::ScanDir(char *root)
    {
       ...
    
       m_pThreadParams = params; 
    
       CreateThread(NULL , 0 , RunLyricsThread, this, 0 , &dwChildId);
       ...
    }
    Do I necessarily need another function, or can I make the LyricsThread function a static?
    "I don't suffer from insanity but enjoy every minute of it" - Edgar Allen Poe

    http://www.Bloodware.net - Developing free software for the community.

  11. #11
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    Do I necessarily need another function, or can I make the LyricsThread function a static?
    You can... While it is not using non-static members of the class.
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  12. #12
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Strong recommendation: use the Boost.Thread library, and you don't have to worry about this stuff.

    http://www.boost.org/
    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

  13. #13
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    Quote Originally Posted by nvoigt View Post
    but then you wasted your only parameter on "this" and you have to use a member variable to actually pass anything meaningful to your thread:
    Unless you put your variables in a struct and pass a pointer to the struct, which is the common practice when spawning worker threads.

Popular pages Recent additions subscribe to a feed