5

I used CreateThread function to write a class like C# BackgroundWorker in C++.My code:

BackgroundWorker.h:

class BackgroundWorker
{
    private :
        HANDLE _threadHandle;
        unsigned int _threadCallcounter;
        DWORD _threadID;
    public:
        BackgroundWorker();
        ~BackgroundWorker();
        virtual DWORD WINAPI Function(LPVOID vpPram);
}

BackgroundWorker.cpp:

#include "BackgroundWorker.h"
void BackgroundWorker::DoWork()
{
    this->_threadHandle = CreateThread(NULL,
        0,this->Function,&this->_threadCallcounter,
        0, &this->_threadID); // !!!***This part throws an error***!!!
}

Then I created another class that derived from BackgroundWorker:

ListenThread.cpp:

class ListenThread :public BackgroundWorker
{
    DWORD WINAPI Function(LPVOID vpPram)
    {
        //DO somthing...
        return 0;
    }
};

But that line gives me the following error:

non - standard syntax; use '&' to create a pointer to member

krlzlx
  • 5,752
  • 14
  • 47
  • 55
  • What do you mean for `this->Function`? Invoke it? Pass the address of the function? – songyuanyao Mar 09 '16 at 09:50
  • but you do aware of `std::thread` , right? – David Haim Mar 09 '16 at 11:25
  • Ditch CreateThread (which noone should be using in C++ code, it was mentioned everywhere 15 years ago), and switch to std::thread. – SergeyA Mar 09 '16 at 14:17
  • @SergeyA: If `std::thread` did offer the same features as `CreateThread` (or `_beginthreadex`), you would have a point. The truth is, it doesn't. Try creating a thread in suspended state using `std::thread`, for example. – IInspectable Jun 16 '17 at 14:10
  • @IInspectable, first of all, CreateThread should **never** be used in C++ code. This much is established and, I hope, non-controversial. As for using `std::thread` vs `_beginthreadex`, I do not see OP using any extra functionality of the latter. Obviously, there are some features of native threads which are not exposed through `std::thread`, but unless they are used, `std::thread` should be preferred. – SergeyA Jun 16 '17 at 14:42
  • @SergeyA: I was commenting on your blanket statement to always use `std::thread` in C++ code, which is easily refuted, because `std::thread` simply doesn't offer the entire range of functionality. Besides, there really is nothing wrong with using `CreateThread` in a C++ Windows application, as long as the thread function doesn't call the CRT. Again, a blanket statement without rationale, that's easily rebutted. – IInspectable Jun 16 '17 at 14:48
  • @IInspectable, how do you know if you are going to call CRT or not? It's hard to imagine a modern C++ application which doesn't call CRT at some point. Since there is no downside of using `_beginthreadex`, one should simply make a hard rule of always using it and be done with that. So this is not refuted in any way. I never made a blanket statement of never using native thread API, my message was directly to OP in regards with OP's code. – SergeyA Jun 17 '17 at 13:39
  • @SergeyA: You know that you aren't calling the CRT by not calling the CRT. Regardless, you keep missing the point: I am providing rationale for when to use what, while you insist to unconditionally use *X* over *Y*. – IInspectable Jun 17 '17 at 13:41
  • @IInspectable, it is you who are missing the point. You do not use CRT **now**, and you create a thread with `CreateThread`, nobody remembers how threads are created, and 3 months later a second developer comes in and starts calling CRT (which is a **very reasonable** thing to do in C++ program). Voila. So you didn't provide any rationale of using `CreateThread` in C++ programs at all. And there is none. You also put the words which I didn't say into my mouth and fight those (pretending I said that there never use case for native thread routines), I have no idea why. – SergeyA Jun 17 '17 at 13:45
  • @SergeyA: I stated facts: It is safe to call `CreateThread` in a C++ application, when your thread function doesn't use the CRT. I never made any statements as to the feasibility or maintainability. Fact is, there are valid reasons to call `CreateThread`. It is more common to use `_beginthreadex`, though. – IInspectable Jun 17 '17 at 13:47
  • @IInspectable, so far, you didn't give any valid reasons to use `CreateThread`. It safe in a limited number of cases, but it is unsafe in more broad scope. In contrast, `_beginthreadex` is always safe. Give me one reason to use `CreateThread` instead of `_beginthreadex`. – SergeyA Jun 17 '17 at 13:54
  • @SergeyA: One obvious reason to use `CreateThread` instead of `_beginthreadex`: You aren't using the CRT (and `_beginthreadex` is not even available). – IInspectable Jun 17 '17 at 14:00
  • @IInspectable, well, I guess, if you know the whole application doesn't use CRT, than you are right, CreateThread is the way. The idea on no-CRT didn't cross my mind, and I am not sure why someone would do this, but OK, there might be reasons I am not aware of. – SergeyA Jun 17 '17 at 14:04

2 Answers2

3

The function pointer that CreateThread expects must have this signature:

DWORD WINAPI ThreadProc(LPVOID lpParameter);

When you create a member function it gets an invisible "this" parameter as first argument, so you declare something like this implicitly:

DWORD WINAPI ThreadProc(BackgroundWorker *this, LPVOID lpParameter);

Create a static member function to omit the this pointer and if you need that pointer inside the thread routine pass it as the void * parameter

Serve Laurijssen
  • 9,266
  • 5
  • 45
  • 98
1

Your error message means you need to pass pointer to function as &Function, not Function in DoWork.

Unfortunately fixing this won't help. CreateThread doesn't work with (non-static) member functions. A solution is to create a static method to use as the actual thread start function.

Check this example:

#include <Windows.h>
#include <iostream>

class BackgroundWorker
{
private :
    HANDLE _threadHandle;
    DWORD _threadID;

public:
    static DWORD WINAPI StaticThreadStart(void * Param) {
        BackgroundWorker * This = static_cast<BackgroundWorker *>(Param);
        return This->Function();
    }

    virtual DWORD Function() {
        return 0;
    }

    void DoWork() {
        _threadHandle = CreateThread(NULL, 0, StaticThreadStart, this, 0, &_threadID);
    }
};

class ListenThread : public BackgroundWorker {
    DWORD Function() override {
        std::cout << "Working...\n";
        return 0;
    }
};

int main()
{
    ListenThread cl;
    cl.DoWork();

    // Call pause to wait for new thread in this example
    system("pause");
    return 0;
}
Lukáš Bednařík
  • 2,578
  • 2
  • 15
  • 30
  • You shouldn't be using `CreateThread` for threads that use the CRT (which you are). This is [documented](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453.aspx): *"A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and _endthreadex functions for thread management rather than CreateThread and ExitThread; [...]. If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions."* – IInspectable Jun 16 '17 at 14:06