简体   繁体   中英

C++ serial thread executor

Coming from a Java environment (specifically Android) I've never had any problems with executing some code in a new thread without blocking the main thread. As I have to work with C++ now I have stumbled upon the follwing issue.

A client code executes my native (C++) code through JNI:

JNIEXPORT jbyteArray JNICALL
Java_com_native_project_NativeInterface_processData(JNIEnv *env, jobject instance, jbyteArray inputData_) {
    vector<unsigned char> inputData = jbyteArrayToBytes(env, inputData_);
    const vector<unsigned char> &result = getDataProcessor(env, instance).processData(inputData);
    return bytesTojbyteArray(env, result);
}

DataProcessor getDataProcessor(JNIEnv *env, jobject instance) {
    return DataProcessor(env, instance);
}

Then in my DataProcessor I want to do two thigs:

  • process the data and return it ASAP
  • write the data to activity log (eg. database) without delaying the response (so first return the response and then log the data)

Example code:

class BasicAsync {
private:
    void logToDB(const vector<unsigned char> &inputData) {
        // connect to DB and write data to it
    }

    vector<unsigned char> compute(const vector<unsigned char> &inputData) {
        vector<unsigned char> result = vector<unsigned char>();
        // rocket-science computation in here
        return result;
    }

public:
    vector<unsigned char> processData(const vector<unsigned char> &inputData) {
        // perform data computation and produce output
        vector<unsigned char> result = compute(inputData);

        // create a thread that writes the data to activity log without delaying the response return
        logToDB(inputData);

        //return result while data is written to activity log
        return result;
    }
}

My main concers are:

  1. Is it possible in C++ (I'm using C++ 11)?
  2. If it takes a while to write the data to database what happens to the DataProcessor object during that time (as it should be destroyed after returning response via JNI as its lifetime scope ends - maybe I'm missing something here)?
  3. Is there any serial thread executor so that I could write a few things to the database (they would be put into a FIFO queue and persisted in sequence in the same thread)?
  1. Yes
  2. Consider a variant of the Active Object Pattern to implement a serial execution queue to do your long-running work that must be serialised:
#include <thread>
#include <mutex>
#include <functional>
#include <queue>

class SerialExecutionQueue
{
public:
    typedef std::function<void()>   QueueItem;

    SerialExecutionQueue() :
    m_shouldQuit(false),
    m_executor([this]()
       {
           executor();
       })
    {

    }

    void enqueueWork(QueueItem item)
    {
        {
            std::lock_guard<std::mutex> l(m_mutex);
            m_queue.push(item);
        }
        m_cv.notify_all();
    }

    void executor()
    {
        while (!m_shouldQuit)
        {
            std::unique_lock<std::mutex> lock(m_mutex);
            while (m_queue.size())
            {
                auto item = m_queue.front();
                m_queue.pop();
                m_mutex.unlock();
                item();
                m_mutex.lock();
            }
            m_cv.wait(lock);
        }
    }

private:
    bool                    m_shouldQuit;
    std::condition_variable m_cv;
    std::mutex              m_mutex;
    std::queue<QueueItem>   m_queue;
    std::thread             m_executor;
};
int main(int argc, const char * argv[])
{

    SerialExecutionQueue queue;

    queue.enqueueWork([]()
          {
              std::cout << "Did some work 1" <<std::endl;
          });


    queue.enqueueWork([]()
          {
              std::cout << "Did some work 2" <<std::endl;
          });

    sleep(1);

    queue.enqueueWork([]()
          {
              std::cout << "Did some work 3" <<std::endl;
          });

    sleep(10);
    return 0;
}

Output:

Did some work 1
Did some work 2
Did some work 3

Prior to 2011, one had to use native APIs like pthreads directly or deploy third party wrapper libs, like those from boost, but since 2011, C++ offers a quite fat standardized thread interface.

Maybe you first have a look at that yourself, try it, and add more specific questions to your post; I will then extend this answer accordingly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM