c++、pthread 和静态回调。 "this" returns 指向派生的基础 class inctead 的指针(第 2 部分)
c++ , pthread and static callbacks. "this" returns a pointer to the base class inctead of the derived one (part 2)
此线程已启动 here 但由于缺少一个完全好的示例(并且为了避免删除所有该问题),它在此处重写。
因此,在下面的示例中,void cppthread::ThreadedFunc()
被派生为作为单独的线程执行。相反,我更喜欢 void ThreadedWrite::ThreadedFunc()
被执行。我怎样才能做到这一点? (代码后面有更多细节)
cppthread.hpp
#ifndef CPPTHREAD_HPP
#define CPPTHREAD_HPP
#include <pthread.h>
using namespace std;
class cppthread
{
public:
cppthread();
virtual ~cppthread();
virtual void threadedFunc();
///parentObj (ie "this" pte from caller") is
///necessary in order to execute the correct
///threadedFunc() even when the derived class
///wants to spawn a thread.
int spawn(void *parentObj = NULL);
void terminate();
protected:
pthread_mutex_t mtx;
bool exitThread;
private:
/* add your private declarations */
int join();
pthread_t threadId;
};
#endif /* CPPTHREAD_HPP */
cppthread.cpp
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "cppthread.hpp"
void* threadCallback(void* obj);
cppthread::cppthread()
{
exitThread = false;
pthread_mutex_init(&mtx, NULL);
}
cppthread::~cppthread()
{
if (!exitThread)
terminate();
pthread_mutex_destroy(&mtx);
}
void cppthread::threadedFunc()
{
while ( !exitThread )
{
printf("Hello from cppthread::threadfunc. This should not be run once derived and redefined.\n");
}
if (exitThread)
{
printf("graceful exit from cppthread::threadfunc. This should not be run once derived and redefined.\n");
}
pthread_exit((void*)0);
}
int cppthread::spawn(void* parentObj)
{
int ret;
printf("parentObj = %p\n", parentObj);
if (parentObj == NULL)
{
ret = pthread_create(&threadId, 0, &threadCallback, this);
printf("cppthread_create with \"this\" \n");
}
else
{
ret = pthread_create(&threadId, 0, &threadCallback, parentObj);
printf("cppthread_create with parentObj\n");
}
if (ret != 0)
{
printf("cppthread_create error\n");
exit(EXIT_FAILURE);
}
else
{
//printf("cppthread::threadID= %lu\n",threadId);
}
return ret;
}
void cppthread::terminate()
{
exitThread = true;
join();
}
int cppthread::join()
{
int status , ret;
//printf("cppthread::join_threadID= %lu\n",threadId);
ret = pthread_join(threadId,(void**)&status);
if (ret != 0)
{
printf("cppthread_join error: ");
switch (ret)
{
case EDEADLK: printf("deadlock\n"); break;
case EINVAL: printf("thread not joinable\n"); break;
case ESRCH: printf("threadID not found\n"); break;
default : printf("unknown error\n"); break;
}
}
return status;
}
//----------------------------------------------------------------------
void* threadCallback(void* obj)
{
static_cast<cppthread*>(obj)->threadedFunc();
return(0);
} // callback
threadedwrite.hpp
#ifndef THREADEDWRITE_HPP
#define THREADEDWRITE_HPP
#include "cppthread.hpp"
using namespace std;
class ThreadedWrite : public cppthread
{
public:
ThreadedWrite(ThreadedWrite* mySelf);
virtual ~ThreadedWrite();
void threadedFunc();
void rrdupdate_thread();
///inherited significant members: from cppthread
/// int spawn();
/// void terminate();
///protected
/// pthread_mutex_t mtx;
/// bool exitThread;
private:
ThreadedWrite* instancePtr;
};
#endif /* THREADEDWRITE_HPP */
threadedwrite.cpp
#include <iostream>
#include "threadedwrite.hpp"
ThreadedWrite::ThreadedWrite(ThreadedWrite* mySelf):instancePtr(mySelf)
{
cout << "instancePtr = " << instancePtr << endl;
}
ThreadedWrite::~ThreadedWrite()
{
}
void ThreadedWrite::threadedFunc()
{
if ( !exitThread )
{
cout << "this is the ThreadedWrite::threadedFunc() running!" << endl;
}
else
{
cout << "ThreadedWrite::threadedFunc must exist now" << endl;
}
pthread_exit((void*)0);
}
void ThreadedWrite::rrdupdate_thread()
{
cout << "about to spawn" << endl;
spawn(instancePtr);
}
main.cpp
#include <iostream>
#include "threadedwrite.hpp"
using namespace std;
//-------main body------------------------------------------------------
int main(int argc, char* argv[])
{
ThreadedWrite thrrdupd(&thrrdupd);
cout << "hello from main 1 " << &thrrdupd << endl;
thrrdupd.rrdupdate_thread();
cout << "hello from main 2 " << &thrrdupd << endl;
return 0;
}
以上产生输出(对我来说):
instancePtr = 0x7fff39d17860
hello from main 1 0x7fff39d17860
about to spawn
parentObj = 0x7fff39d17860
cppthread_create with parentObj
hello from main 2 0x7fff39d17860
graceful exit from cppthread::threadfunc. This should not be run once derived and redefined.
因此,从派生的 class "ThreadedWrite" 中执行上述 cppthread::spawn()
调用,实际上提供了指向 callback()
函数的 "this" 指针,该函数指向 cppthread::ThreadedFunc()
,而不是 ThreadedWrite::ThreadedFunc()
。
您还可以看到我尝试(通过 "instancePtr" 基础结构)将指向 "ThreadedWrite" 实例的指针传递回回调函数。但这也失败了。
此外,最好我希望 cppthread class 尽可能通用,以便能够在可能的情况下使用它。
请注意,如果我从 threadedwrite.cpp 中删除 "spawn(instancePtr)",并像这样从 main.cpp 中调用 spawn
int main(int argc, char* argv[])
{
ThreadedWrite thrrdupd(&thrrdupd);
cout << "hello from main 1 " << &thrrdupd << endl;
thrrdupd.rrdupdate_thread();
thrrdupd.spawn();
cout << "hello from main 2 " << &thrrdupd << endl;
return 0;
}
我得到的输出是预期的(和想要的)输出,它看起来像这样:
instancePtr = 0x7ffd24b04ed0
hello from main 1 0x7ffd24b04ed0
about to spawn
parentObj = (nil)
cppthread_create with "this"
hello from main 2 0x7ffd24b04ed0
this is the ThreadedWrite::threadedFunc() running!
您需要等待线程终止,然后才能从 main
return,因为这会破坏您的对象。
否则你有竞争条件:
- 线程已启动。
thrrdupd
在您离开时开始被破坏 main
。
~ThreadedWrite
运行;此时对象不再是 ThreadedWrite
而是 cppthread
.
~cppthread
运行并等待线程。
- 线程调用回调,因为对象现在具有动态类型
cppthread
,cppthread::threadedFunc
被调用。
5. 有可能发生在 3. 之前,在这种情况下您将获得预期的输出。
如果您确保等待线程在第 3 步完成,那么它将正常工作。也许你可以在 ~ThreadedWrite
?
中调用 terminate
此线程已启动 here 但由于缺少一个完全好的示例(并且为了避免删除所有该问题),它在此处重写。
因此,在下面的示例中,void cppthread::ThreadedFunc()
被派生为作为单独的线程执行。相反,我更喜欢 void ThreadedWrite::ThreadedFunc()
被执行。我怎样才能做到这一点? (代码后面有更多细节)
cppthread.hpp
#ifndef CPPTHREAD_HPP
#define CPPTHREAD_HPP
#include <pthread.h>
using namespace std;
class cppthread
{
public:
cppthread();
virtual ~cppthread();
virtual void threadedFunc();
///parentObj (ie "this" pte from caller") is
///necessary in order to execute the correct
///threadedFunc() even when the derived class
///wants to spawn a thread.
int spawn(void *parentObj = NULL);
void terminate();
protected:
pthread_mutex_t mtx;
bool exitThread;
private:
/* add your private declarations */
int join();
pthread_t threadId;
};
#endif /* CPPTHREAD_HPP */
cppthread.cpp
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "cppthread.hpp"
void* threadCallback(void* obj);
cppthread::cppthread()
{
exitThread = false;
pthread_mutex_init(&mtx, NULL);
}
cppthread::~cppthread()
{
if (!exitThread)
terminate();
pthread_mutex_destroy(&mtx);
}
void cppthread::threadedFunc()
{
while ( !exitThread )
{
printf("Hello from cppthread::threadfunc. This should not be run once derived and redefined.\n");
}
if (exitThread)
{
printf("graceful exit from cppthread::threadfunc. This should not be run once derived and redefined.\n");
}
pthread_exit((void*)0);
}
int cppthread::spawn(void* parentObj)
{
int ret;
printf("parentObj = %p\n", parentObj);
if (parentObj == NULL)
{
ret = pthread_create(&threadId, 0, &threadCallback, this);
printf("cppthread_create with \"this\" \n");
}
else
{
ret = pthread_create(&threadId, 0, &threadCallback, parentObj);
printf("cppthread_create with parentObj\n");
}
if (ret != 0)
{
printf("cppthread_create error\n");
exit(EXIT_FAILURE);
}
else
{
//printf("cppthread::threadID= %lu\n",threadId);
}
return ret;
}
void cppthread::terminate()
{
exitThread = true;
join();
}
int cppthread::join()
{
int status , ret;
//printf("cppthread::join_threadID= %lu\n",threadId);
ret = pthread_join(threadId,(void**)&status);
if (ret != 0)
{
printf("cppthread_join error: ");
switch (ret)
{
case EDEADLK: printf("deadlock\n"); break;
case EINVAL: printf("thread not joinable\n"); break;
case ESRCH: printf("threadID not found\n"); break;
default : printf("unknown error\n"); break;
}
}
return status;
}
//----------------------------------------------------------------------
void* threadCallback(void* obj)
{
static_cast<cppthread*>(obj)->threadedFunc();
return(0);
} // callback
threadedwrite.hpp
#ifndef THREADEDWRITE_HPP
#define THREADEDWRITE_HPP
#include "cppthread.hpp"
using namespace std;
class ThreadedWrite : public cppthread
{
public:
ThreadedWrite(ThreadedWrite* mySelf);
virtual ~ThreadedWrite();
void threadedFunc();
void rrdupdate_thread();
///inherited significant members: from cppthread
/// int spawn();
/// void terminate();
///protected
/// pthread_mutex_t mtx;
/// bool exitThread;
private:
ThreadedWrite* instancePtr;
};
#endif /* THREADEDWRITE_HPP */
threadedwrite.cpp
#include <iostream>
#include "threadedwrite.hpp"
ThreadedWrite::ThreadedWrite(ThreadedWrite* mySelf):instancePtr(mySelf)
{
cout << "instancePtr = " << instancePtr << endl;
}
ThreadedWrite::~ThreadedWrite()
{
}
void ThreadedWrite::threadedFunc()
{
if ( !exitThread )
{
cout << "this is the ThreadedWrite::threadedFunc() running!" << endl;
}
else
{
cout << "ThreadedWrite::threadedFunc must exist now" << endl;
}
pthread_exit((void*)0);
}
void ThreadedWrite::rrdupdate_thread()
{
cout << "about to spawn" << endl;
spawn(instancePtr);
}
main.cpp
#include <iostream>
#include "threadedwrite.hpp"
using namespace std;
//-------main body------------------------------------------------------
int main(int argc, char* argv[])
{
ThreadedWrite thrrdupd(&thrrdupd);
cout << "hello from main 1 " << &thrrdupd << endl;
thrrdupd.rrdupdate_thread();
cout << "hello from main 2 " << &thrrdupd << endl;
return 0;
}
以上产生输出(对我来说):
instancePtr = 0x7fff39d17860
hello from main 1 0x7fff39d17860
about to spawn
parentObj = 0x7fff39d17860
cppthread_create with parentObj
hello from main 2 0x7fff39d17860
graceful exit from cppthread::threadfunc. This should not be run once derived and redefined.
因此,从派生的 class "ThreadedWrite" 中执行上述 cppthread::spawn()
调用,实际上提供了指向 callback()
函数的 "this" 指针,该函数指向 cppthread::ThreadedFunc()
,而不是 ThreadedWrite::ThreadedFunc()
。
您还可以看到我尝试(通过 "instancePtr" 基础结构)将指向 "ThreadedWrite" 实例的指针传递回回调函数。但这也失败了。
此外,最好我希望 cppthread class 尽可能通用,以便能够在可能的情况下使用它。
请注意,如果我从 threadedwrite.cpp 中删除 "spawn(instancePtr)",并像这样从 main.cpp 中调用 spawn
int main(int argc, char* argv[])
{
ThreadedWrite thrrdupd(&thrrdupd);
cout << "hello from main 1 " << &thrrdupd << endl;
thrrdupd.rrdupdate_thread();
thrrdupd.spawn();
cout << "hello from main 2 " << &thrrdupd << endl;
return 0;
}
我得到的输出是预期的(和想要的)输出,它看起来像这样:
instancePtr = 0x7ffd24b04ed0
hello from main 1 0x7ffd24b04ed0
about to spawn
parentObj = (nil)
cppthread_create with "this"
hello from main 2 0x7ffd24b04ed0
this is the ThreadedWrite::threadedFunc() running!
您需要等待线程终止,然后才能从 main
return,因为这会破坏您的对象。
否则你有竞争条件:
- 线程已启动。
thrrdupd
在您离开时开始被破坏main
。~ThreadedWrite
运行;此时对象不再是ThreadedWrite
而是cppthread
.~cppthread
运行并等待线程。- 线程调用回调,因为对象现在具有动态类型
cppthread
,cppthread::threadedFunc
被调用。
5. 有可能发生在 3. 之前,在这种情况下您将获得预期的输出。
如果您确保等待线程在第 3 步完成,那么它将正常工作。也许你可以在 ~ThreadedWrite
?
terminate