rwozniak
rwozniak

Reputation: 1386

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:

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)?

Upvotes: 2

Views: 972

Answers (2)

marko
marko

Reputation: 9159

  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

Upvotes: 3

decltype_auto
decltype_auto

Reputation: 1736

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.

Upvotes: 0

Related Questions