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

问题描述

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



所以,在下面的例子中,



否则你有一个竞争条件:


  1. 线程已启动。

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

  3. 线程调用回调,因为对象现在具有动态类型 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部分)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 09:10
查看更多