Intercept "Q" and company in KeyPress - keyboard

I am trying to find a way to intercept all keys, but apparently all defaults commands are still there, functioning properly. I've started with the cone example, and tried both vtkCallbackCommand and SetInteractorStyle, as suggested in the examples:
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkCylinderSource.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkCallbackCommand.h>
#include <vtkCommand.h>
#include <array>
class KeyPressInteractorStyle : public vtkInteractorStyleTrackballCamera
{
public:
static KeyPressInteractorStyle* New();
vtkTypeMacro(KeyPressInteractorStyle, vtkInteractorStyleTrackballCamera);
virtual void OnKeyPress() override
{
vtkRenderWindowInteractor* rwi = this->Interactor;
std::string key = rwi->GetKeySym();
std::cout << "Pressed " << key << std::endl;
if (key == "Up")
{
std::cout << "The up arrow was pressed." << std::endl;
}
// Handle a "normal" key
if (key == "q" || key == "Q")
{
std::cout << "The q key was pressed." << std::endl;
return;
}
// DO NOT Forward events
//vtkInteractorStyleTrackballCamera::OnKeyPress();
}
};
vtkStandardNewMacro(KeyPressInteractorStyle);
void KeypressCallbackFunction(vtkObject* caller, long unsigned int eventId,
void* clientData, void* callData)
{
std::cout << "Keypress callback" << std::endl;
vtkRenderWindowInteractor* iren = static_cast<vtkRenderWindowInteractor*>(caller);
std::cout << "Pressed: " << iren->GetKeySym() << std::endl;
}
int main(int, char*[])
{
vtkNew<vtkNamedColors> colors;
std::array<unsigned char, 4> bkg{{26, 51, 102, 255}};
colors->SetColor("BkgColor", bkg.data());
vtkNew<vtkCylinderSource> cylinder;
cylinder->SetResolution(8);
vtkNew<vtkPolyDataMapper> cylinderMapper;
cylinderMapper->SetInputConnection(cylinder->GetOutputPort());
vtkNew<vtkActor> cylinderActor;
cylinderActor->SetMapper(cylinderMapper);
cylinderActor->GetProperty()->SetColor(colors->GetColor4d("Tomato").GetData());
cylinderActor->RotateX(30.0);
cylinderActor->RotateY(-45.0);
vtkNew<vtkRenderer> renderer;
renderer->AddActor(cylinderActor);
renderer->SetBackground(colors->GetColor3d("BkgColor").GetData());
// Zoom in a little by accessing the camera and invoking its "Zoom" method.
renderer->ResetCamera();
renderer->GetActiveCamera()->Zoom(1.5);
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->SetSize(800, 800);
renderWindow->AddRenderer(renderer);
renderWindow->SetWindowName("Cylinder");
vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
renderWindowInteractor->SetRenderWindow(renderWindow);
// VIA STYLE
// vtkNew<KeyPressInteractorStyle> style;
// renderWindowInteractor->SetInteractorStyle(style);
// style->SetCurrentRenderer(renderer);
// VIA CALLBACK
vtkNew<vtkCallbackCommand> keypressCallback;
keypressCallback->SetCallback(KeypressCallbackFunction);
renderWindowInteractor->AddObserver(vtkCommand::KeyPressEvent, keypressCallback);
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
In both cases, "Q" still quits, "W" still goes into wireframe.
Is there a way to properly hanlde all key events, even the default ones?

For those shortcuts (i.e. letters) there is also the CharEvent that is send, linked to the vtkInteractorStyle::OnChar method where quit and wireframe are implemented.
So either override it in your style (in addition to the OnKeyPress), either handle the event with the observer mechanism.

Related

Why sleep() in a thread cannot be interrupted by signal in my code?

#include <iostream>
#include <thread>
#include <signal.h>
#include <unistd.h>
void handler(int sig){
std::cout << "handler" << std::endl;
}
void func() {
sleep(100);
perror("sleep err:");
}
int main(void) {
signal(SIGINT, handler);
std::thread t(func);
pthread_kill(t.native_handle(), SIGINT);
perror("kill err:");
t.join();
return 0;
}
If I put sleep() inside main function, and send a signal by pressing ctrl+c, sleep will be interrupted and return immediately with perror() saying it's interrupted.
But with the code above, the "handler" in handler function will be printed, but sleep will not return and the program keeps running. The output of this program is:
kill err:: Success
handler
And if I replace sleep() with recvfrom(), recvfrom() will not be interrupted even it's inside the main thread.
#include <vector>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
void SigHandler(int sig){
std::cout << "handler" << std::endl;
}
int main(void) {
signal(SIGINT, SigHandler);
int bind_fd_;
if ((bind_fd_ = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::cout << "socket creation failed " << strerror(errno) << std::endl;
}
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(12345);
if (bind(bind_fd_, reinterpret_cast<const struct sockaddr *>(&servaddr),
sizeof(servaddr)) < 0) {
std::cout << "socket bind failed " << strerror(errno) << std::endl;
}
struct sockaddr_in cliaddr;
socklen_t cliaddr_len = sizeof(cliaddr);
std::vector<char> buffer(10*1024*1024,0);
std::cout << "Wait for new request"<< std::endl;
int n = 0;
while (n == 0) {
std::cout << "before recvfrom" << std::endl;
n = recvfrom(bind_fd_, buffer.data(), buffer.size(), 0,
reinterpret_cast<struct sockaddr *>(&cliaddr), &cliaddr_len);
// sleep(100);
perror("recvfrom err: ");
std::cout << "recv " << n << " bytes from " << cliaddr.sin_port<< std::endl;
}
}
I don't know what is wrong with my code, hoping your help, thanks
At the time you direct the signal to the thread, that thread has not yet proceeded far enough to block in sleep(). Chances are that it has not even been scheduled for the first time. Change the code to something like
std::thread t(func);
sleep(5); // give t enough time to arrive in sleep()
pthread_kill(t.native_handle(), SIGINT);
and you'll see what you expect.
Note that using signals in a multithreaded program is not usually a good idea because certain aspects are undefined/not-so-clearly defined.
Note also that it is not correct to use iostreams inside a signal handler. Signal handlers run in a context where pretty much nothing is safe to do, much like an interrupt service routine on bare metal. See here for a thorough explanation of that matter.

Using CLOCK_MONOTONIC type in the 'condition variable' wait_for() notify() mechanism

I am using code that runs on ARM (not Intel processor). Running c++11 code example (CODE A) from: http://www.cplusplus.com/reference/condition_variable/condition_variable/wait_for/ to test the wait_for() mechanism. This is not working right - looks like the wait_for() does not wait. In Intel works fine. After some research and using pthread library directly and setting MONOTONIC_CLOCK definition, solves the issue (CODE B).
(Running on ARM is not the issue)
My problem is :
How can I force the C++11 API wait_for() to work with MONOTONIC_CLOCK?
Actually I would like to stay with 'CODE A' but with the support or setting of MONOTONIC_CLOCK.
Thanks
CODE A
// condition_variable::wait_for example
#include <iostream> // std::cout
#include <thread> // std::thread
#include <chrono> // std::chrono::seconds
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable, std::cv_status
std::condition_variable cv;
int value;
void read_value() {
std::cin >> value;
cv.notify_one();
}
int main ()
{
std::cout << "Please, enter an integer (I'll be printing dots): \n";
std::thread th (read_value);
std::mutex mtx;
std::unique_lock<std::mutex> lck(mtx);
while
(cv.wait_for(lck,std::chrono::seconds(1))==std::cv_status::timeout)
{
std::cout << '.' << std::endl;
}
std::cout << "You entered: " << value << '\n';
th.join();
return 0;
}
CODE B
#include <sys/time.h>
#include <unistd.h>
#include <iostream> // std::cout
#include <thread> // std::thread
#include <chrono> // std::chrono::seconds
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable, std::cv_status
const size_t NUMTHREADS = 1;
pthread_mutex_t mutex;
pthread_cond_t cond;
int value;
bool done = false;
void* read_value( void* id )
{
const int myid = (long)id; // force the pointer to be a 64bit integer
std::cin >> value;
done = true;
printf( "[thread %d] done is now %d. Signalling cond.\n", myid, done
);
pthread_cond_signal( &cond );
}
int main ()
{
struct timeval now;
pthread_mutexattr_t Attr;
pthread_mutexattr_init(&Attr);
pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex, &Attr);
pthread_condattr_t CaAttr;
pthread_condattr_init(&CaAttr);
pthread_condattr_setclock(&CaAttr, CLOCK_MONOTONIC);
pthread_cond_init(&cond, &CaAttr);
std::cout << "Please, enter an integer:\n";
pthread_t threads[NUMTHREADS];
int t = 0;
pthread_create( &threads[t], NULL, read_value, (void*)(long)t );
struct timespec ts;
pthread_mutex_lock( &mutex );
int rt = 0;
while( !done )
{
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_sec += 1;
rt = pthread_cond_timedwait( & cond, & mutex, &ts );
std::cout << "..." << std::endl;
}
pthread_mutex_unlock( & mutex );
std::cout << "You entered: " << value << '\n';
return 0;
}
The documentation for std::condition_variable::wait_for says:
A steady clock is used to measure the duration.
std::chrono::steady_clock:
Class std::chrono::steady_clock represents a monotonic clock. The time points of this clock cannot decrease as physical time moves forward.
Unfortunately, this is gcc Bug 41861 (DR887) - (DR 887)(C++0x) does not use monotonic_clock that it uses system_clock instead of steady_clock for condition variables.
One solution is to use wait_until (be sure to read Notes section) function that allows to specify durations relative to a specific clock. E.g.:
cv.wait_until(lck, std::chrono::steady_clock::now() + std::chrono::seconds(1))

How would I stop a std::thread in a controlled manner

I have a program where I start multiple, long running threads (such as a REST-API). On primed signals (e.g SIGHUP) I would like to be able to shut down all threads cleanly (by waiting for them to exit). Below follows some code from a thispointer article that illustrated a good idea on how to do this
#include <thread>
#include <iostream>
#include <assert.h>
#include <chrono>
#include <future>
void threadFunction(std::future<void> futureObj)
{
std::cout << "Thread Start" << std::endl;
while (futureObj.wait_for(std::chrono::milliseconds(1)) ==
std::future_status::timeout)
{
std::cout << "Doing Some Work" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
std::cout << "Thread End" << std::endl;
}
int main()
{
// Create a std::promise object
std::promise<void> exitSignal;
//Fetch std::future object associated with promise
std::future<void> futureObj = exitSignal.get_future();
// Starting Thread & move the future object in lambda function by reference
std::thread th(&threadFunction, std::move(futureObj));
//Wait for 10 sec
std::this_thread::sleep_for(std::chrono::seconds(10));
std::cout << "Asking Thread to Stop" << std::endl;
//Set the value in promise
exitSignal.set_value();
//Wait for thread to join
th.join();
std::cout << "Exiting Main Function" << std::endl;
return 0;
}
However, as one might have noticed this concept has a critical drawback: the exitSignal will have to be emitted before th.join() is called.
In a situation where one wants to listen to a signal, e.g using signal(SIGHUP, callback) this is of course impractical.
My question is: are there better concepts for shutting down multiple threads? How would I go about them? I think using a promise is not a bad idea, I just haven't found a way with it to solve my problem.
You can use std::notify_all_at_thread_exit() on a std::condition_variable.
Here is an example:
#include <mutex>
#include <thread>
#include <condition_variable>
#include <cassert>
#include <string>
std::mutex m;
std::condition_variable cv;
bool ready = false;
std::string result; // some arbitrary type
void thread_func()
{
thread_local std::string thread_local_data = "42";
std::unique_lock<std::mutex> lk(m);
// assign a value to result using thread_local data
result = thread_local_data;
ready = true;
std::notify_all_at_thread_exit(cv, std::move(lk));
} // 1. destroy thread_locals;
// 2. unlock mutex;
// 3. notify cv.
int main()
{
std::thread t(thread_func);
t.detach();
// do other work
// ...
// wait for the detached thread
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, [] { return ready; });
// result is ready and thread_local destructors have finished, no UB
assert(result == "42");
}
Source: cppreference.com

Can't exit exec loop in Qt

Well, I have created a program which picks up the input signal from serial input. I can successfully receive the data transmitted from the device through UART. I want to terminate the thread after achieving certain conditions( such as receiving more than 5 bytes, etc.) I think the problem is how to terminate the thread in Qt correctly, but I couldn't find the way. The program seems falls into deadlock after calling the exec() in the sub function. Can anyone help with that problem? Thank you very much!
Here's my header file:
#ifndef SERIALTHREAD
#define SERIALTHREAD
#include <QtSerialPort/QSerialPort>
#include <QDebug>
#include <QString>
#include <QThread>
#include <QtCore>
#include <iostream>
#include <fstream>
class SerialControlThread : public QThread
{
Q_OBJECT
public:
explicit SerialControlThread(QString ComPort,QObject *parent = 0);
~SerialControlThread(); // Destructor
bool openSerialPort();
void closeSerialPort();
void run();
bool TelltoExit();
void StarttoRun();
private:
int DataCount;
QString ComPortNumber;
QSerialPort *serial;
int* VoltageStorage; // Total 3 channels, each channel takes 10 data
unsigned int Channel_A[10]; // Channel_A is for Phase Tx s
int DataCountIndexA; // This is how many data has been sent to the buffer;
int SentDataCount;
unsigned char StoreDataBuffer[2];
unsigned char TotalDataCounter;
std::ofstream write;
signals:
void BufferisFull(int*);
void TimeToQuit();
public slots:
private slots:
void readData();
void handleError(QSerialPort::SerialPortError error);
};
#endif // SERIALTHREAD
This is the.cpp
#include "serialcontrol.h"
#include <iostream>
SerialControlThread::SerialControlThread(QString ComPort,QObject *parent) :
QThread(parent),ComPortNumber(ComPort)
{
DataCountIndexA=0;
DataCount=0;
serial = new QSerialPort(this);
connect(this,SIGNAL(TimeToQuit()),this,SLOT(quit()));\
connect(serial, SIGNAL(readyRead()), this, SLOT(readData()));
connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this,
SLOT(handleError(QSerialPort::SerialPortError)));
for (int i=0;i<10;i++)
Channel_A[i]=0;
}
SerialControlThread::~SerialControlThread()
{
this->closeSerialPort();
delete serial;
}
bool SerialControlThread::openSerialPort()
{
// std::cout << "Hey I am in serial function" << std::endl;
serial->setPortName(ComPortNumber) ;
serial->setBaudRate(QSerialPort::Baud9600); //This can be set through menu in the future
serial->setDataBits(QSerialPort::Data8); // A packets contains 8 bits ( 3 for signature bits)
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
if (!(serial->open(QIODevice::ReadWrite))) {
return false; // return false when the device can't be opened
}else
{
return true;} // return true when the device is avalaible
}
void SerialControlThread::closeSerialPort()
{
if (serial->isOpen())
serial->close();
}
void SerialControlThread::handleError(QSerialPort::SerialPortError error)
{
}
void SerialControlThread::readData()
{
QByteArray data=serial->read(100);
const char *TempChar=data.data();
std::cout << TempChar << std::endl;
DataCount++;
if(DataCount>=4)
{
std::cout << "I am bigger than 4" << std::endl;
this->quit();
}
}
}
void SerialControlThread::run()
{
}
bool SerialControlThread::TelltoExit()
{
}
void SerialControlThread::StarttoRun()
{
// Sending the msp430 S to activate the following sequence
const char *temp="S";
serial->write(temp);
serial->waitForBytesWritten(30000);
this->exec();
}
This is the main.cpp
#include <QCoreApplication>
#include <QtSerialPort/QSerialPortInfo>
#include <QList>
#include <iostream>
#include <QString>
#include <QDebug>
#include <QSerialPort>
#include "serialcontrol.h"
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int AvailablePorts=QSerialPortInfo::availablePorts().count();
QList<QSerialPortInfo> SerialObject=QSerialPortInfo::availablePorts();
cout << "There are total: " << SerialObject.count() << " available ports " << endl << endl;
QString description;
for (int i=0;i<AvailablePorts;i++)
{
cout << "The " << i+1 << " com port is :";
qDebug() << SerialObject[i].portName();
qDebug() << "Description : " << SerialObject[i].description();
qDebug() << "Manufacturer: " << SerialObject[i].manufacturer();
cout << endl;
}
SerialControlThread *RunThread=new SerialControlThread(SerialObject[0].portName(),&a);
cout << RunThread->openSerialPort() << endl;
RunThread->StarttoRun();
cout << "I am out of here" << endl;
delete RunThread;
return a.exec();
}
I wish to close the thread( back to the main function) when the buffer has received more than 4 data, but it doesn't.
It is my output
There are total: 1 available ports
The 1 com port is :"COM8"
Description : "MSP430 Application UART"
Manufacturer: "Texas Instruments"
1
0
1
2
3
I am bigger than 4
4
I am bigger than 4
5
I am bigger than 4
6
I am bigger than 4
7
I am bigger than 4
8
I am bigger than 4
9
I am bigger than 4
Apparently, the program gets stuck in a loop. I have tried some solutions, but none of these worked.
StartToRun calls QThread::exec in the wrong thread: you call it in the main thread, but it's supposed to be called in the thread itself - from within run().
Alas, SerialControlThread doesn't have to be a thread. Making it a thread forces it to be used in a dedicated thread - that should be a choice left to its user. Perhaps the thread would be shared among other serial controllers, or perhaps it'll do just fine in the main thread. Thus, it should be an object that handles serial data, that has a thread-safe interface so that you can move it to another thread if you wish - but would still work fine in the main thread, and thus has to handle data asynchronously without blocking.
Considering whether one needs to control the worker thread's run status so tightly: an idle thread consumes no resources - its event loop is blocked waiting on new events, its stack eventually gets paged out if there's memory pressure. If one intends to "wake" the thread for each operation, there's no need to be explicit about it: the event loop in the thread behaves that way be default and by design: it wakes when there are new events, such as incoming data, otherwise it sleeps. One shouldn't be stopping the thread then.
The example below shows a very minimal implementation. On the whole it's not very useful other than to demonstrate brevity as a contrast to the length of code in the question - in spite of identical limited functionality. Presumably you have a more complex communications protocol that you wish to handle. You may wish to consider the use of QDataStream read transactions to make the reader code more expressive, and using a state machine to represent the protocol.
// https://github.com/KubaO/stackoverflown/tree/master/questions/serial-galore-42241570
#include <QtWidgets>
#include <QtSerialPort>
// See https://stackoverflow.com/q/40382820/1329652
template <typename Fun> void safe(QObject * obj, Fun && fun) {
Q_ASSERT(obj->thread() || qApp && qApp->thread() == QThread::currentThread());
if (Q_LIKELY(obj->thread() == QThread::currentThread() || !obj->thread()))
return fun();
struct Event : public QEvent {
using F = typename std::decay<Fun>::type;
F fun;
Event(F && fun) : QEvent(QEvent::None), fun(std::move(fun)) {}
Event(const F & fun) : QEvent(QEvent::None), fun(fun) {}
~Event() { fun(); }
};
QCoreApplication::postEvent(
obj->thread() ? obj : qApp, new Event(std::forward<Fun>(fun)));
}
class SerialController : public QObject {
Q_OBJECT
QSerialPort m_port{this};
QByteArray m_rxData;
void onError(QSerialPort::SerialPortError error) {
Q_UNUSED(error);
}
void onData(const QByteArray & data) {
m_rxData.append(data);
qDebug() << "Got" << m_rxData.toHex() << "(" << m_rxData.size() << ") - done.";
emit hasReply(m_rxData);
}
void onData() {
if (m_port.bytesAvailable() >= 4)
onData(m_port.readAll());
}
public:
explicit SerialController(const QString & port, QObject * parent = nullptr) :
QObject{parent}
{
m_port.setPortName(port);
connect(&m_port, static_cast<void(QSerialPort::*)(QSerialPort::SerialPortError)>(&QSerialPort::error),
this, &SerialController::onError);
}
~SerialController() { qDebug() << __FUNCTION__; }
bool open() {
m_port.setBaudRate(QSerialPort::Baud9600);
m_port.setDataBits(QSerialPort::Data8);
m_port.setParity(QSerialPort::NoParity);
m_port.setStopBits(QSerialPort::OneStop);
m_port.setFlowControl(QSerialPort::NoFlowControl);
return m_port.open(QIODevice::ReadWrite);
}
/// This method is thread-safe.
void start() {
safe(this, [=]{
m_port.write("S");
qDebug() << "Sent data";
});
}
Q_SIGNAL void hasReply(const QByteArray &);
void injectData(const QByteArray & data) {
onData(data);
}
};
QDebug operator<<(QDebug dbg, const QSerialPortInfo & info) {
dbg << info.portName();
if (!info.description().isEmpty())
dbg << " Description: " << info.description();
if (!info.manufacturer().isEmpty())
dbg << " Manufacturer: " << info.manufacturer();
return dbg;
}
// A thread that starts on construction, and is always safe to destruct.
class RunningThread : public QThread {
Q_OBJECT
using QThread::run; // final
public:
RunningThread(QObject * parent = nullptr) : QThread(parent) { start(); }
~RunningThread() { qDebug() << __FUNCTION__; quit(); wait(); }
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
auto const ports = QSerialPortInfo::availablePorts();
if (ports.isEmpty())
qFatal("No serial ports");
int n{};
qDebug() << "Available ports:";
for (auto & port : ports)
qDebug() << "port[" << n++ << "]: " << port;
SerialController ctl{ports.at(5).portName()};
if (!ctl.open())
qFatal("Open Failed");
// Optional: the controller will work fine in the main thread.
if (true) ctl.moveToThread(new RunningThread{&ctl}); // Owns its thread
// Let's pretend we got a reply;
QTimer::singleShot(1000, &ctl, [&ctl]{
ctl.injectData("ABCD");
});
QObject::connect(&ctl, &SerialController::hasReply, ctl.thread(), &QThread::quit);
QObject::connect(&ctl, &SerialController::hasReply, [&]{
qDebug() << "The controller is done, quitting.";
app.quit();
});
ctl.start();
return app.exec();
}
#include "main.moc"

C++11 non-blocking, long-running, producer consumer threads

I am trying to teach myself C++11 threading, and I would like to start a background producer thread at the beginning of the application, and have it run until application exit. I would also like to have consumer thread (which also runs for the life of the application).
A real-world example would be a producer thread listening on a Com port for incoming GPS data. Once a full message had been accumulated, it could be parsed to see if it was a message of interest, then converted into a string (say), and 'delivered back' to be consumed (update current location, for example).
My issue is I haven't been able to figure out how to do this without blocking the rest of the application when I 'join()' on the consumer thread.
Here is my very simplified example that hopefully shows my issues:
#include <QCoreApplication>
#include <QDebug>
#include <thread>
#include <atomic>
#include <iostream>
#include <queue>
#include <mutex>
#include <chrono>
#include "threadsafequeuetwo.h"
ThreadSafeQueueTwo<int> goods;
std::mutex mainMutex;
std::atomic<bool> isApplicationRunning = false;
void theProducer ()
{
std::atomic<int> itr = 0;
while(isApplicationRunning)
{
// Simulate this taking some time...
std::this_thread::sleep_for(std::chrono::milliseconds(60));
// Push the "produced" value onto the queue...
goods.push(++itr);
// Diagnostic printout only...
if ((itr % 10) == 0)
{
std::unique_lock<std::mutex> lock(mainMutex);
std::cout << "PUSH " << itr << " on thread ID: "
<< std::this_thread::get_id() << std::endl;
}
// Thread ending logic.
if (itr > 100) isApplicationRunning = false;
}
}
void theConsumer ()
{
while(isApplicationRunning || !goods.empty())
{
int val;
// Wait on new values, and 'pop' when available...
goods.waitAndPop(val);
// Here, we would 'do something' with the new values...
// Simulate this taking some time...
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// Diagnostic printout only...
if ((val % 10) == 0)
{
std::unique_lock<std::mutex> lock(mainMutex);
std::cout << "POP " << val << " on thread ID: "
<< std::this_thread::get_id() << std::endl;
}
}
}
int main(int argc, char *argv[])
{
std::cout << "MAIN running on thread ID: "
<< std::this_thread::get_id() << std::endl;
// This varaiable gets set to true at startup, and,
// would only get set to false when the application
// wants to exit.
isApplicationRunning = true;
std::thread producerThread (theProducer);
std::thread consumerThread (theConsumer);
producerThread.detach();
consumerThread.join(); // BLOCKS!!! - how to get around this???
std::cout << "MAIN ending on thread ID: "
<< std::this_thread::get_id() << std::endl;
}
The ThreadSafeQueueTwo class is the thread safe queue implementation taken almost exactly as is from the "C++ Concurrency In Action" book. This seems to work just fine. Here it is if anybody is interested:
#ifndef THREADSAFEQUEUETWO_H
#define THREADSAFEQUEUETWO_H
#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>
template<typename T>
class ThreadSafeQueueTwo
{
public:
ThreadSafeQueueTwo()
{}
ThreadSafeQueueTwo(ThreadSafeQueueTwo const& rhs)
{
std::lock_guard<std::mutex> lock(myMutex);
myQueue = rhs.myQueue;
}
void push(T newValue)
{
std::lock_guard<std::mutex> lock(myMutex);
myQueue.push(newValue);
myCondVar.notify_one();
}
void waitAndPop(T& value)
{
std::unique_lock<std::mutex> lock(myMutex);
myCondVar.wait(lock, [this]{return !myQueue.empty(); });
value = myQueue.front();
myQueue.pop();
}
std::shared_ptr<T> waitAndPop()
{
std::unique_lock<std::mutex> lock(myMutex);
myCondVar.wait(lock, [this]{return !myQueue.empty(); });
std::shared_ptr<T> sharedPtrToT (std::make_shared<T>(myQueue.front()));
myQueue.pop();
return sharedPtrToT;
}
bool tryPop(T& value)
{
std::lock_guard<std::mutex> lock(myMutex);
if (myQueue.empty())
return false;
value = myQueue.front();
myQueue.pop();
return true;
}
std::shared_ptr<T> tryPop()
{
std::lock_guard<std::mutex> lock(myMutex);
if (myQueue.empty())
return std::shared_ptr<T>();
std::shared_ptr<T> sharedPtrToT (std::make_shared<T>(myQueue.front()));
myQueue.pop();
return sharedPtrToT;
}
bool empty()
{
std::lock_guard<std::mutex> lock(myMutex);
return myQueue.empty();
}
private:
mutable std::mutex myMutex;
std::queue<T> myQueue;
std::condition_variable myCondVar;
};
#endif // THREADSAFEQUEUETWO_H
Here's the output:
I know there are obvious issues with my example, but my main question is how would I run something like this in the background, without blocking the main thread?
Perhaps an even better way of trying to solve this is, is there a way that every time the producer has 'produced' some new data, could I simply call a method in the main thread, passing in the new data? This would be similar to queued signal/slots it Qt, which I am big fan of.

Resources