I am very surprised by the strange exception, that I got.
class Threads {
public:
Threads() {}
~Threads() {}
void StartThread(int (*p)()); //pointer to a function
private:
HANDLE hThread;
DWORD dwThreadID;
};
Method StartThread should receive pointer to my function (that will be run in another thread).
This function is simple. (as you can see it is situated outside the class Threads):
int MyThread()
{
return 0;
}
And this is method of creating thread:
inline void Threads::StartThread(int (*p)())
{
hThread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)(*p)(),
NULL,
0,
&dwThreadID);
if (hThread == NULL)
{
return;
}
}
Here compiler get error: cannot convert parameter 3 from 'int' to 'LPTHREAD_START_ROUTINE'. That why I did the casting.
In main function I create object of type Threads and I try to call method StartThread. As parameter I send pointer to the function MyThread.
Threads *thread1;
thread1 = new Threads();
thread1->StartThread(MyThread);
I thought MyThread must start in another thread. But the function MyTread always runs in Main Thread!!! And only after MyThread ends, another thread starts and then I get this exception:
Unhandled exception at 0x00000000 in ThreadClass.exe: 0xC0000005: Access violation.
I need clever advice!
The call convention is wrong:
LPTHREAD_START_ROUTINE is a __stdcall method not a __cdecl method, see the documentation here: http://msdn.microsoft.com/en-us/library/aa964928.aspx.
It looks like you are actually calling the function on this line...
(LPTHREAD_START_ROUTINE)(*p)()
...and it returns an int that you're casting. That just can't work. How about:
(LPTHREAD_START_ROUTINE)p
...instead?
Related
I've been re-architecting some fairly procedural C++ into something more classy. The original code runs just fine and part of it spins up a new thread to do some file cleaning. The function that does this cleaning is the entry point for the new thread. See code below. NB: This code won't execute, but it shows the principle that worked.
#include <stdlib.h>
// Structure for passing application data to a new thread.
typedef struct threadData {
networkShare* netArchive;
rig* rigInfo;
rigDatabase* dbConn;
networkConn* netConn;
char* logBuffer;
} THREADDATA;
// Global handle to a mutex object
// Used to control access to the inter thread log buffer
HANDLE ghMutex;
DWORD WINAPI cleanLocalArchive(LPVOID lpParam) {
THREADDATA* p_threadData = (THREADDATA*)lpParam;
// ... Do stuff ...
return <<something>>;
}
int main(int argc, char** argv) {
// Variables for local archive thread
HANDLE h_CleanerThread = 0;
THREADDATA* p_threadData = NULL;
DWORD dwThreadId;
// Create a mutex with no initial owner
ghMutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
if (ghMutex == NULL) {
printf("CreateMutex error: %d\n", GetLastError());
return 1;
}
// Declare the data structure for passing app setting to a new Thread and populate it.
p_threadData = DBG_NEW THREADDATA;
p_threadData->netArchive = &rigArchive;
p_threadData->rigInfo = &thisRig;
p_threadData->logBuffer = (char*)malloc(BUF_SIZE);
p_threadData->dbConn = &archiveDB;
p_threadData->netConn = &netConnection;
// Initialise p_threadData->logBuffer in case we never put anything else in there.
sprintf_s(p_threadData->logBuffer, BUF_SIZE, "");
// Start a new thread
h_CleanerThread = CreateThread(
NULL, // default security attributes
0, // use default stack size
cleanLocalArchive, // thread function name
p_threadData, // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
// ... Do other stuff ...
return 0;
}
I've now refactored the code into classes and the function "cleanLocalArchive" is a member function of the application class AircatFeeder. When I call this member function in the in CreateThread() I get various errors depending on what I do to the code:
As-is: call line = "cleanLocalArchive,"
error C3867: 'AirCatFeeder::cleanLocalArchive': non-standard syntax; use '&' to create a pointer to member
So I add in an ampersand: call line = "&cleanLocalArchive,"
error C2276: '&': illegal operation on bound member function expression
error C2660: 'CreateThread': function does not take 5 arguments
After some head scratching and Google-Foo I found this link which I hoped would solve the issue. It certainly shed some light on the why. I created a wrapper function outside the class and tried calling that. The function and its call was as follows:
Function call:
// Start a new thread
h_CleanerThread = CreateThread(
NULL, // default security attributes
0, // use default stack size
trampoline, // thread function name
p_threadData, // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
Wrapper Function:
DWORD trampoline(LPVOID data) {
AirCatFeeder* scheduler = static_cast<AirCatFeeder*>(data);
return scheduler->cleanLocalArchive(data);
}
However, I still ended up with the same issues/error messages. Whether I call the member function, or the wrapper function, IntelliSense still reports a similar error message:
argument of type "DWORD(*)(LPVOID lpParam)" is incompatible with parameter of type "LPTHREAD_START_ROUTINE"
Hopefully it is now clear what I'm trying to achieve. Can someone please educate me on what I'm doing wrong? Thanks.
Answer courtesy of Hans Passant. See Comments on question:
The trampoline is missing WINAPI in its definition.
I have a class and a library (lwip). For some reasons I need to call library's function of thread creation like :
/** The only thread function:
* Creates a new thread
* #param name human-readable name for the thread (used for debugging purposes)
* #param thread thread-function
* #param arg parameter passed to 'thread'
* #param stacksize stack size in bytes for the new thread (may be ignored by ports)
* #param prio priority of the new thread (may be ignored by ports) */
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int
stacksize, int prio);
Inside this function we call pthread:
code = pthread_create(&tmp,NULL,(void *(*)(void *)) function, arg);
My call looks like :
sys_thread_new("main_thread",(lwip_thread_fn)&this->main_thread, NULL,
DEFAULT_THREAD_STACKSIZE,DEFAULT_THREAD_PRIO);
My class method works fine, but I need to change some fielsd of CURRENT class (like 'state'
or else) I have an Idea to pass a pointer to current class to that thread and in thread function change class fields. Some kind of:
sys_thread_new("main_thread",(lwip_thread_fn)&this->main_thread, (void*)this,
DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
Then in main_thread:
void lwip::main_thread(void *arg) {
lwip *p = (lwip*)arg;
p->state = 1;
}
Something like that. But it seems I do something wrong -
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff6e8e700 (LWP 4985)]
0x0000000000403a75 in lwip::main_thread (this=0x7fffffffe4f0, arg=0x80) at
../src/lwip.cpp:50
50 p->state = 1;
There are two problems here: If the main_thread member function is a static member function, you pass a pointer to it using &lwip::main_thread, no casting should be needed. If the function is not static, then you must make it static.
The other problem is that if the instance (this) you pass to the thread function is destructed, the thread function now has a pointer to a destructed object. Be careful with temporary object or passing instances by value.
If the actual thread function can't be static, you can easily solve it with a static wrapper function:
class lwip
{
...
private:
void main_thread() { ... }
static void* main_thread_wrapper(void* arg)
{
reinterpret_cast<lwip*>(arg)->main_thread();
return nullptr;
}
};
...
sys_thread_new("main_thread", &lwip::main_thread_wrapper, this,
DEFAULT_THREAD_STACKSIZE,DEFAULT_THREAD_PRIO);
If you have to cast the pointer to function to get
pthread_create to compile, you have undefined behavior.
If the goal is to call a member function in a different thread,
you need to wrap the call in an extern "C" function. This
means no members and no templates; in the simplest case:
extern "C" void*
startThread( void* p )
{
static_cast<T*>(p)->f();
}
and pass the address of startThread as third argument and
a pointer to the object as fourth. If inheritance is involved,
you must ensure that the fourth argument has the same type as
that in the cast in startThread, e.g.:
pthread_create( &tmp, nullptr, &startThread, static_cast<Base*>( pointerToDerived ) );
if startThread casts to Base*.
If you need arguments to the function as well, you need to pass
a pointer to a struct with both the pointer to the object and
the additional arguments. You also need to ensure that the
lifetime of this struct is sufficient, so that there is no risk
of the thread accessing an already inexistant object. This
often means an additional conditional variable, to ensure that
the thread calling pthread_create doesn't continue before the
new thread has made a copy of all of the relevant data. (Both
Boost threads and the C++11 threads do this for you. It's only
necessary if you need additional data, other than just the
pointer to the object, in the new thread.)
This can get painful if you need to do it for many different
types, and downright impossible if the class in question is
a template. In such cases, one common solution is to use
a Thread object, along the lines of:
class Thread
{
public:
virtual void* run() = 0;
};
and a starter function:
namespace {
extern "C" void*
doStartThread( void* p )
{
return static_cast<Thread*>( p )->run();
}
}
pthread_t
startThread( Thread* thread )
{
pthread_t results;
if ( pthread_create( &results, nullptr, doStartThread, thread ) != 0 ) {
throw std::runtime_error( "Could not create thread" );
}
}
Afterwards, you inherit from Thread, overriding the run
function with whatever you want (and adding any additional data
you might need); the derived class can even be a template.
Again, the lifetime of the Thread object is an issue; the
solution I've usually used has been to require it to be
dynamically allocated, and then delete it at the end of
doStartThread. It's a very good idea to catch it in an
std::unique_ptr in doStartThread, although you still want to
catch exceptions in this function, since otherwise they will
kill the process. And don't forget the delete if
pthread_create fails (since the caller has passed over
ownership. If you really want to be sure:
namespace {
extern "C" void*
doStartThread( void* p )
{
std::unique_ptr<Thread*> object( static_cast<Thread*>( p ) );
try {
return object->run();
} catch ( ... ) {
return somethingElseToReportTheError;
}
}
}
pthread_t
startThread( std::unique_ptr<Thread> thread )
{
pthread_t results;
if ( pthread_create( &results, nullptr, doStartThread, thread.get() ) != 0 ) {
throw std::runtime_error( "Could not create thread" );
}
thread.release(); // AFTER the call has succeeded!
}
I've used this technique successfully in a number of
applications (using std::auto_ptr, since there was no
std::unique_ptr then); typically, the fact that you need to
use dynamic allocation is not an issue, and it solves the
lifetime issue quite nicely. (The alternative would be to use
a conditional variable, blocking the original thread until the
new thread had copied everything over.)
Note that by using a unique_ptr in the interface, you
effectively block the calling thread from further access to the
thread object, by robbing it of its pointer to the object. This
offers an additional guarantee with regards to thread safety.
But of course, this additional guarantee (and the solution to
the lifetime issues) only applies to the Thread object itself,
and not to anything it might point to.
I'm using the method 'pthread_create' in my program, and get a segmentation fault INSIDE THIS METHOD.
What can possibly cause this? I'm calling this function with the correct arguments' types!
this is the code:
pthread_t* _daemon;
void* writer(void* arg){
// stuff that dont involve "arg"...
}
int initdevice(){
if(pthread_create(_daemon, NULL, &writer, NULL) != 0) //seg in this line
{
cerr << "system error\n";
return ERR_CODE;
}
return SUCCESS;
}
int main () {
initdevice();
return 0;
}
Note: I've tried to run it also without the '&' before the calling to writer in pthread_create, and also - we've tried sending to this method some void* argument instead of the last NULL argument.
Your probelem is here:
pthread_t* _daemon;
This should be:
pthread_t daemon;
Then change the call to pthread_create:
if(pthread_create(&daemon, NULL, &writer, NULL) != 0)
The idea is that pthread_create takes a pointer to an existing pthread_t object so that it can fill in the details. You can think of it as the C version of a constructor. Initially the pthread_t object is uninitialized this initializes it.
In addition your code is still probably not going to always work as you do not wait for the thread to finish. Make sure your main thread does not finish before all the children:
int main ()
{
initdevice();
pthread_join(daemon, NULL); // wait for the thread to exit first.
return 0;
}
you must allocate _daemon variable with new or malloc function, because you have use of a pointer. like bellow :
pthread_t* _daemon;
_daemon = new pthread_t;
Here is my code which contains error:
void ClassA::init()
{
HANDLE hThread;
data thread; // "thread" is an object of struct data
hThread = CreateThread(NULL, 0, C1::threadfn, &thread, 0, NULL);
}
DWORD WINAPI ClassA::threadfn(LPVOID lpParam)
{
data *lpData = (data*)lpParam;
}
Error:
error C3867: 'ClassA::threadfn': function call missing argument list; use '&ClassA::threadfn' to create a pointer to member
What is the proper way to make the worker thread working in a single class?
The thread creation functions are not aware of C++ classes; as such, your thread entry point must be either a static class member function, or a non-member function. You can pass in the this pointer as the lpvThreadParam parameter to the CreateThread() function, then have the static or non-member entry point function simply call the threadfn() function via that pointer.
If the threadfn() function is static, then make sure you put & before C1::threadfn.
Here's a simple example:
class MyClass {
private:
static DWORD WINAPI trampoline(LPVOID pSelf);
DWORD threadBody();
public:
HANDLE startThread();
}
DWORD WINAPI MyClass::trampoline(LPVOID pSelf) {
return ((MyClass)pSelf)->threadBody();
}
DWORD MyClass::threadBody() {
// Do the actual work here
}
HANDLE MyClass::startThread() {
return CreateThread(NULL, 0, &MyClass::trampoline, (LPVOID)this, 0, NULL);
}
You're using MFC, according to the tags. CreateThread is the Win32 C API, you should look at CWinThread instead.
Follow the advice in the warning error, then this should work provided the member function threadfn is static.
What happens if you do what the error says?
CreateThread(NULL, 0, &C1::threadfn, &thread, 0, NULL); // now passing pointer
This assumes that threadfn() is static.
I use C++ to implement a thread class. My code shows in the following.
I have a problem about how to access thread data.
In the class Thread, I create a thread use pthread_create() function. then it calls EntryPoint() function to start thread created. In the Run function, I want to access the mask variable, it always shows segment fault.
So, my question is whether the new created thread copy the data in original class? How to access the thread own data?
class Thread {
public:
int mask;
pthread_t thread;
Thread( int );
void start();
static void * EntryPoint (void *);
void Run();
};
Thread::Thread( int a) {
mask =a;
}
void Thread::Run() {
cout<<"thread begin to run" <<endl;
cout << mask <<endl; // it always show segmentfault here
}
void * Thread::EntryPoint(void * pthis) {
cout << "entry" <<endl;
Thread *pt = (Thread *) pthis;
pt->Run();
}
void Thread::start() {
pthread_create(&thread, NULL, EntryPoint, (void *)ThreadId );
pthread_join(thread, NULL);
}
int main() {
int input_array[8]={3,1,2,5,6,8,7,4};
Thread t1(1);
t1.start();
}
I'm not familiar with the libraries you're using, but how does EntryPoint know that pthis is a pointer to Thread? Thread (this) does not appear to be passed to pthread_create.
It's great that you're attempting to write a Thread class for educational purposes. However, if you're not, why reinvent the wheel?
pThis is most likely NULL, you should double check that you're passing the correct arguments to pthread_create.
Basically, the problem is as soon as you start your thread, main exits and your local Thread instance goes out of scope. So, because the lifetime of your thread object is controlled by another thread, you've already introduced a race condition.
Also, I'd consider joining a thread immediately after you've created it in Thread::start to be a little odd.