lundi 25 mai 2020

pthread_join hangs forever C++

I am running this g_test where I simply initialize and close a client.

TEST(safIpc, createAndCloseClient)
{
    std::shared_ptr<fnv::ipcsvc::IpcSvc> safIpc = std::make_shared<fnv::ipcsvc::IpcSvc>();
    const std::string& app1 {"/testApp1"};
    const std::string& groupName {"wir_clients"};
    fnv::ipcsvc::IpcSvcAttrMq attr(fnv::ipcsvc::IpcSvcAttrType::MQ_CLIENT,
                                   app1,
                                   groupName,
                                   "/server");
    std::shared_ptr<IpcSvcTestSafHandler> msgHandler = std::make_shared<IpcSvcTestSafHandler>();

    // initialize the ipc library
    IpcSvcPriv::SharedPtr ipcPrivData {nullptr};
    fnv::ipcsvc::IpcSvcRet ret = safIpc->init(attr, msgHandler, ipcPrivData);
    EXPECT_EQ(ret, fnv::ipcsvc::IpcSvcRet::SUCCESS);
    EXPECT_NE(ipcPrivData, nullptr);

    ret = safIpc->close(ipcPrivData, app1); //HANGS here
    EXPECT_EQ(fnv::ipcsvc::IpcSvcRet::SUCCESS, ret);
}

In init I create 3 threads: (here is the relevant part of the init code):

1- A process thread 2- a Receive thread 3- A timer thread

    int rc = pthread_create(&m_timerThread,
                            NULL,
                            &IpcSvcImpl::timer_start,
                            this);

    if (rc != 0)
    {
        ipcSvcLog(LOGE, "Failed to create timer thread!");
        close(tmpPrivData,
              attr.getAppId());
        return error;
    }
    pthread_setname_np(m_timerThread,
                       "IpcSvcTimerThread");
}

// Start the worker threads
int rc = pthread_create(&m_receiveThread,
                        NULL,
                        &IpcSvcImpl::receive,
                        this);
if (rc != 0)
{
    //TODO some error log
    close(tmpPrivData,
          attr.getAppId());
    return error;
}
pthread_setname_np(m_receiveThread,
                   "IpcSvcReceiveThread");

rc = pthread_create(&m_processThread,
                    NULL,
                    &IpcSvcImpl::process,
                    this);
if (rc != 0)
{
    //TODO some error log
    close(tmpPrivData,
          attr.getAppId());
    return error;
}
pthread_setname_np(m_processThread,
                   "IpcSvcProcessThread");

Here is the close function:

IpcSvcRet IpcSvcImpl::close(IpcSvcPriv::SharedPtr privateData,
                            const std::string& appId)
{
    if (!privateData)
    {
        //TODO log about client not providing sane private data
        return IpcSvcRet::FAIL;
    }

    // acquire the mutex and set close called to true
    {
        std::lock_guard<std::mutex> guard(m_closeMtx);
        m_closed = true;
    }

    if (m_msgQueue)
    {
        m_msgQueue->mutexInit();

        // writing dummy message to process thread
        std::pair<std::array<uint8_t, IPCSVC_MAX_MSG_SIZE>, ssize_t> queueMsg;
        m_msgQueue->enqueue(queueMsg);
    }

    // writing dummy message to receive thread
    uint32_t buffer = 0;
    sendData(privateData,
             (void*)&buffer,
             sizeof(uint32_t),
             appId);

    pthread_join(m_receiveThread,
                 NULL);
    pthread_join(m_processThread,
                 NULL);

    if (m_isClient)
    {
        m_cv.notify_one();
        printf("timer thread hangs\n"); // HANGS HERE ///////////////////////////////////////
        pthread_join(m_timerThread,
                     NULL);
//This line is never reached..
    }

    delete m_msgQueue;
    m_msgQueue  = nullptr;

    // close the ipc layer
    if (m_ipc)
    {
        m_ipc->close();
        delete m_ipc;
        m_ipc = nullptr;
    }

    m_clientsList.clear();
    m_hbManager = { };

    return IpcSvcRet::SUCCESS;
}

Here is the timer_start function: The timer thread is a timer that is keeps looping forever unless the fc->m_closed is set to true. It triggers fc->timerExpiry() every 2 seconds.

// timer thread entry
void* IpcSvcImpl::timer_start(void *arg)
{
    if (!arg)
    {
        return nullptr;
    }
    printf("starting timer\n");
    IpcSvcImpl* fc = static_cast<IpcSvcImpl *>(arg);
    std::unique_lock<std::mutex> lock(fc->m_closeMtx);
    while (!(fc->m_closed))
    {
        printf("Entering loop\n");

        lock.unlock();
        auto expireAt = std::chrono::steady_clock::now() +
                        std::chrono::seconds(fc->getTimerInterval());
        fc->timerExpiry();
        lock.lock();
        printf("here?\n");
        fc->m_cv.wait_until(lock, expireAt);
        printf("Here 2\n");

    }
    printf("Exited loop\n\n");


    return nullptr;
}

The output of the unittest:

[----------] 5 tests from safIpc
[ RUN      ] safIpc.createAndCloseClient
starting timer
Entering loop
closing..
timer thread hangs

pthread join hangs forever, I am not sure why. The "here" prints are never hit, which seems odd.

Thanks for the help!

Aucun commentaire:

Enregistrer un commentaire