c ++,pthread和静态回调。 “这个”返回指向派生类的基类的指针(第2部分) [英] c++ , pthread and static callbacks. "this" returns a pointer to the base class inctead of the derived one (part 2)

查看:160
本文介绍了c ++,pthread和静态回调。 “这个”返回指向派生类的基类的指针(第2部分)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此主题已开始,但由于缺乏一个完全良好的例子(为了避免删除所有的问题)它在这里重写。



所以,在下面的例子中, 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(即thispte from caller)是
///,以便执行正确的
/// threadedFunc(),即使派生类
///想生成一个线程
int spawn(void * parentObj = NULL);
void terminate();

protected:
pthread_mutex_t mtx ;
bool exitThread;

private:
/ *添加您的私有声明* /
int join();

pthread_t threadId;
};

#endif / * CPPTHREAD_HPP * /

cppthread.cpp

  #include< stdio.h> 
#include< errno.h>
#include< stdlib.h>

#includecppthread.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。这不应该运行一次derived和redefined.\\\
);
}
if(exitThread)
{
printf(graceful exit from cppthread :: threadfunc。This should not be run once derived and redefined.\\\
);
}
pthread_exit((void *)0);
}

int cppthread :: spawn(void * parentObj)
{
int ret;
printf(parentObj =%p\\\
,parentObj);
if(parentObj == NULL)
{
ret = pthread_create(& threadId,0,& threadCallback,this);
printf(cppthread_create with \this \\\\
);
}
else
{
ret = pthread_create(& threadId,0,& threadCallback,parentObj);
printf(cppthread_create with parentObj \\\
);
}

if(ret!= 0)
{
printf(cppthread_create error\ n);
exit(EXIT_FAILURE);
}
else
{
// printf(cppthread :: threadID =%lu\\\
,threadId);
}
return ret;
}

void cppthread :: terminate()
{
exitThread = true;
join();
}

int cppthread :: join()
{
int status,ret;
// printf(cppthread :: join_threadID =%lu\\\
,threadId);
ret = pthread_join(threadId,(void **)& status);
if(ret!= 0)
{
printf(cppthread_join error:);
switch(ret)
{
case EDEADLK:printf(deadlock\\\
);打破;
case EINVAL:printf(thread not joinable\\\
);打破;
case ESRCH:printf(threadID not found\\\
);打破;
默认值:printf(unknown error\\\
);打破;
}
}
return status;
}

// ----------------------------------- -----------------------------------
void * threadCallback(void * obj)
{
static_cast< cppthread *>(obj) - > threadedFunc();
returns(0);
} // callback

threadedwrite.hpp

  #ifndef THREADEDWRITE_HPP 
#define THREADEDWRITE_HPP

#includecppthread.hpp

using namespace std ;

类ThreadedWrite:public cppthread
{
public:
ThreadedWrite(ThreadedWrite * mySelf);
virtual〜ThreadedWrite();

void threadedFunc();
void rrdupdate_thread();

///继承的重要成员:from cppthread
/// int spawn();
/// void terminate();
/// protected
/// pthread_mutex_t mtx;
/// bool exitThread;

private:
ThreadedWrite * instancePtr;
};

#endif / * THREADEDWRITE_HPP * /

threadedwrite.cpp

  #include< iostream> 
#includethreadedwrite.hpp


ThreadedWrite :: ThreadedWrite(ThreadedWrite * mySelf):instancePtr(mySelf)
{
cout< ; instancePtr =< instancePtr<< endl;
}

ThreadedWrite ::〜ThreadedWrite()
{

}

void ThreadedWrite :: threadedFunc b $ b {
if(!exitThread)
{
cout<< 这是ThreadedWrite :: threadedFunc()运行! << endl;
}
else
{
cout< ThreadedWrite :: threadedFunc必须存在<< endl;
}

pthread_exit((void *)0);
}

void ThreadedWrite :: rrdupdate_thread()
{
cout< 即将产卵< endl;
spawn(instancePtr);
}

main.cpp

  #include< iostream> 

#includethreadedwrite.hpp

using namespace std;

// -------主体------------------------------- -----------------------
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;
}

上面产生的输出
$ b instancePtr = 0x7fff39d17860
hello from main 1 0x7fff39d17860
关于spawn
parentObj = 0x7fff39d17860
cppthread_create with parentObj
hello from main 2 0x7fff39d17860
从cppthread :: threadfunc退出。这不应该运行一次派生和重新定义。

所以执行上面的 cppthread :: spawn()调用从派生类ThreadedWrite中实际提供了一个this指向 callback()函数,指向 cppthread :: ThreadedFunc (),而不是 ThreadedWrite :: ThreadedFunc()



您还可以看到我通过instancePtr基础结构)将指向ThreadedWrite实例的指针传递回回调函数。但这也失败了。



此外,最好我想保持cppthread类尽可能一般为了能够使用它在可能的情况下。



注意,如果我从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
要生成
parentObj =(nil)
cppthread_create with this this
hello from main 2 0x7ffd24b04ed0
这是ThreadedWrite :: threadedFunc()运行!


解决方案

您需要等待线程终止



否则你有一个竞争条件:


  1. 线程已启动。

  2. thrrdupd 在你离开 main

  3. 〜ThreadedWrite 此时对象不再是 ThreadedWrite ,而是 cppthread

  4. $ 〜cppthread 运行并等待线程。

  5. 线程调用回调,因为对象现在具有动态类型 cppthread cppthread :: threadedFunc

这可能是5.可能发生在3.之前,在这种情况下你会得到预期的输出。



如果你确保等待线程完成在步骤3.然后它会工作正常。也许你可以在〜ThreadedWrite 里调用 terminate


this thread was started here but due to lack of an altogether good example (and in order to avoid delete all that question) it is re-written here.

So, in the following example, the void cppthread::ThreadedFunc() gets spawned to execute as a separate thread . Instead I would prefer void ThreadedWrite::ThreadedFunc() to be executed. How can I do that? (some more details follow after the code)

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;
}

The above produces the output (for me):

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.

So executing the above cppthread::spawn() call from within the derived class "ThreadedWrite" , actually provides a "this" pointer to callback() function that points to cppthread::ThreadedFunc(), instead of ThreadedWrite::ThreadedFunc().

You can also see that I tried (through the "instancePtr" infrastructure) to pass a pointer to the instance of "ThreadedWrite" back to the callback function. But this failed too.

Also, preferably I would like to keep cppthread class as generic as possible in order to be able to use it in may cases.

Mind you, if I remove "spawn(instancePtr)" from threadedwrite.cpp , and call the spawn from main.cpp like this

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;
}

the output that I get Is the expected (and wanted) one and it looks like this:

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!

解决方案

You need to wait for the thread to terminate before you return from main, because that destroys your object.

Otherwise you have a race condition:

  1. The thread is started.
  2. thrrdupd starts to be destoyed as you leave main.
  3. ~ThreadedWrite runs; at this point the object is no longer a ThreadedWrite but a cppthread.
  4. ~cppthread runs and waits for the thread.
  5. The thread calls the callback and because the object now has dynamic type cppthread, cppthread::threadedFunc is called.

It is possible that 5. might happen before 3., in which case you will get the expected output.

If you make sure you wait for the thread to finish at step 3. then it will work fine. Perhaps you could call terminate inside ~ThreadedWrite?

这篇关于c ++,pthread和静态回调。 “这个”返回指向派生类的基类的指针(第2部分)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆