Multiple thread pause/resume - c++

Main thread uses group of threads to search. First solution (test1) is often creating , waiting - join() and destroying threads. This works but has overhead. I try using mutex and condition_variable, but this not works,. especially for number searching threads>1.
My code:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
using namespace std;
const int NThr = 2;
struct InterchangeData {
bool endflag=false;
mutex chg_mutex;
condition_variable condition;
};
InterchangeData data;
bool execute1(InterchangeData* xchgData) {
for (int i=0; i<10; i++) {
if (xchgData->endflag) return false;
this_thread::sleep_for(chrono::milliseconds(rand()%10 +1 ));
if (rand()%100 == 50) {
lock_guard<mutex> lock(xchgData->chg_mutex);
if (!xchgData->endflag) {
printf("found!");
xchgData->endflag = true;
return true;
}
}
}
return false;
}
bool execute2(InterchangeData* xchgData) {
while (true) {
{
unique_lock<mutex> lock(xchgData->chg_mutex);
xchgData->condition.wait(lock);
}
int ret=2;
if (xchgData->endflag) ret=0;
if (execute1(xchgData)) ret=1;
{
unique_lock<mutex> lock(xchgData->chg_mutex);
xchgData->condition.notify_one();
this_thread::sleep_for(chrono::milliseconds(1));
if (ret==0) return false;
else if (ret==1) return true;
}
}
}
vector<thread*> threads;
typedef bool (*functype)(InterchangeData*);
void start(functype execute) {
for (int i=0; i<NThr; i++) {
auto t = new thread(execute, &data);
threads.push_back(t);
}
}
void stop() {
for (auto t : threads) {
t->join();
delete t;
}
threads.clear();
}
void test1() {
for (int i=0; i<10; i++) {
start(&execute1);
stop();
}
}
void test2() {
start(&execute2);
this_thread::sleep_for(chrono::milliseconds(100));
for (int i=0; i<10; i++) {
{
unique_lock<mutex> lock(data.chg_mutex);
data.condition.notify_one();
this_thread::sleep_for(chrono::milliseconds(1));
}
{
unique_lock<mutex> lock(data.chg_mutex);
data.condition.wait(lock);
}
}
{
unique_lock<mutex> lock(data.chg_mutex);
data.condition.notify_one();
this_thread::sleep_for(chrono::milliseconds(1));
}
stop();
}
int main() {
test2();
return 0;
}
Problem: is possible fast pausing/resuming execute function and main thread using condition_variable,unique_lock and wait/notify_one ?

Related

About `std::conditional_variable`. Why this code snippet stall?

Why this code snippet stall?
The program intends to output firstsecondthird whereas the program stalls after firstsecond has been printed.
#include <condition_variable>
#include <mutex>
#include <thread>
#include <functional>
#include <iostream>
#include <vector>
class Foo {
public:
Foo() {
}
void first(std::function<void()> printFirst)
{
{
std::unique_lock<std::mutex> lk(mutex);
cv1.wait(lk, [this](){return 1==state;});
doing = 1;
// printFirst() outputs "first". Do not change or remove this line.
printFirst();
state = 2;
}
cv2.notify_one();
}
void second(std::function<void()> printSecond)
{
{
std::unique_lock<std::mutex> lk(mutex);
if(state !=2 )
{
if((1 == state)&&(1 != doing))
{
lk.unlock();
cv1.notify_one();
}
}
cv2.wait(lk, [this](){return 2==state;});
doing = 2;
// printSecond() outputs "second". Do not change or remove this line.
printSecond();
state = 3;
}
cv3.notify_one();
}
void third(std::function<void()> printThird)
{
{
std::unique_lock<std::mutex> lk(mutex);
if(state !=3 )
{
if((1 == state)&&(1 != doing))
{
lk.unlock();
cv1.notify_one();
}
else if((2 == state)&&(2 != doing))
{
lk.unlock();
cv2.notify_one();
}
}
cv3.wait(lk, [this](){return 3==state;});
// printThird() outputs "third". Do not change or remove this line.
printThird();
state = 3;
}
}
private:
std::condition_variable cv1;
std::condition_variable cv2;
std::condition_variable cv3;
std::mutex mutex;
int state{1};
int doing{0};
};
int main()
{
Foo foo;
std::vector<std::thread> threads;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.second([]()->void{std::cout <<"second" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.first([]()->void{std::cout <<"first" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.third([]()->void{std::cout <<"third" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::seconds(2));
for(auto itr=threads.begin(); itr!=threads.end(); itr++)
{
itr->join();
}
}
Quoted from the comments of #Igor Tandetnik.
As per the document, which says that
template void wait (unique_lock& lck, Predicate pred);
lck
A unique_lock object whose mutex object is currently locked by
this thread. All concurrent calls to wait member functions of this
object shall use the same underlying mutex object (as returned by
lck.mutex()).
So, cv2.wait(lk, ...) requires that lk actually hold the mutex.
And if lk.unlock(); is removed, this code snippet could work as expected.
#include <condition_variable>
#include <mutex>
#include <thread>
#include <functional>
#include <iostream>
#include <vector>
class Foo {
public:
Foo() {
}
void first(std::function<void()> printFirst)
{
{
std::unique_lock<std::mutex> lk(mutex);
cv1.wait(lk, [this](){return 1==state;});
doing = 1;
// printFirst() outputs "first". Do not change or remove this line.
printFirst();
state = 2;
}
cv2.notify_one();
}
void second(std::function<void()> printSecond)
{
{
std::unique_lock<std::mutex> lk(mutex);
if(state !=2 )
{
if((1 == state)&&(1 != doing))
{
//lk.unlock(); //removed
cv1.notify_one();
}
}
cv2.wait(lk, [this](){return 2==state;});
doing = 2;
// printSecond() outputs "second". Do not change or remove this line.
printSecond();
state = 3;
}
cv3.notify_one();
}
void third(std::function<void()> printThird)
{
{
std::unique_lock<std::mutex> lk(mutex);
if(state !=3 )
{
if((1 == state)&&(1 != doing))
{
//lk.unlock(); //removed
cv1.notify_one();
}
else if((2 == state)&&(2 != doing))
{
//lk.unlock(); //removed
cv2.notify_one();
}
}
cv3.wait(lk, [this](){return 3==state;});
// printThird() outputs "third". Do not change or remove this line.
printThird();
state = 3;
}
}
private:
std::condition_variable cv1;
std::condition_variable cv2;
std::condition_variable cv3;
std::mutex mutex;
int state{1};
int doing{0};
};
int main()
{
Foo foo;
std::vector<std::thread> threads;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.second([]()->void{std::cout <<"second" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.first([]()->void{std::cout <<"first" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.third([]()->void{std::cout <<"third" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::seconds(2));
for(auto itr=threads.begin(); itr!=threads.end(); itr++)
{
itr->join();
}
}
And the code snippet could be improved as this one:
#include <condition_variable>
#include <mutex>
#include <thread>
#include <functional>
#include <iostream>
#include <vector>
// #lc code=start
class Foo {
public:
Foo() {
}
void first(std::function<void()> printFirst)
{
{
std::unique_lock<std::mutex> lk(mutex);
// printFirst() outputs "first". Do not change or remove this line.
printFirst();
state = 2;
}
cv2.notify_one();
}
void second(std::function<void()> printSecond)
{
{
std::unique_lock<std::mutex> lk(mutex);
cv2.wait(lk, [this](){return 2==state;});
// printSecond() outputs "second". Do not change or remove this line.
printSecond();
state = 3;
}
cv3.notify_one();
}
void third(std::function<void()> printThird)
{
{
std::unique_lock<std::mutex> lk(mutex);
cv3.wait(lk, [this](){return 3==state;});
// printThird() outputs "third". Do not change or remove this line.
printThird();
state = 3;
}
}
private:
std::condition_variable cv2;
std::condition_variable cv3;
std::mutex mutex;
int state{1};
};
// #lc code=end
int main()
{
Foo foo;
std::vector<std::thread> threads;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.second([]()->void{std::cout <<"second" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.first([]()->void{std::cout <<"first" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.third([]()->void{std::cout <<"third" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::seconds(2));
for(auto itr=threads.begin(); itr!=threads.end(); itr++)
{
itr->join();
}
}

Producer-Consumer Problem in c++ using pthread

I am currently learning multithreading and semaphores and have been assigned to recreate the problem using only pthread. I found a solution that uses std::thread and have been working to convert it to pthreads, but I am having problems with the pthread_create method.
I am not sure specifically how to turn this statement
pthread_create(&threads[i], NULL, &Producer::run, &p);
into something that works with pthreads.
Here is my whole code for reference
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <deque>
#include <condition_variable>
#include <semaphore.h>
#include <queue>
#ifdef _WIN32
#include <windows.h>
void sleeps(unsigned milliseconds)
{
Sleep(milliseconds);
}
#else
#include <unistd.h>
void sleeps(unsigned milliseconds) {
usleep(milliseconds * 1000); // takes microseconds
}
#endif
class Widget {
public:
int data;
void setData(int data) {
this->data = data;
}
};
class Buffer
{
public:
void add(Widget widget) {
while (true) {
pthread_mutex_lock(&lock);
sharedBuffer.push_back(widget);
pthread_mutex_unlock(&lock);
return;
}
}
Widget remove() {
while(true) {
pthread_mutex_lock(&lock);
Widget backElem = sharedBuffer.back();
sharedBuffer.pop_back();
pthread_mutex_unlock(&lock);
return backElem;
}
}
Buffer() {}
private:
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
std::deque<Widget> sharedBuffer;
};
class Producer{
Buffer& sharedBuffer;
pthread_mutex_t coutMut;
public:
Producer(Buffer& buffer)
: sharedBuffer(buffer), coutMut(PTHREAD_MUTEX_INITIALIZER)
{}
void run() {
while(true) {
Widget widget;
widget.setData(rand() % 10);
sharedBuffer.add(widget);
pthread_mutex_lock(&coutMut);
std::cout << "Added: " << widget.data << "\n";
sleeps(50);
pthread_mutex_unlock(&coutMut);
}
}
};
class Consumer
{
Buffer& sharedBuffer;
pthread_mutex_t coutMut;
public:
Consumer(Buffer& buffer)
: sharedBuffer(buffer), coutMut(PTHREAD_MUTEX_INITIALIZER)
{}
void run() {
while(true) {
Widget widget;
widget = sharedBuffer.remove();
pthread_mutex_lock(&coutMut);
std::cout << "Removed: " << widget.data << "\n";
sleeps(50);
pthread_mutex_unlock(&coutMut);
}
}
};
int main(int argc, char *argv[]) {
typedef std::string string_std;
const int producerT = std::stoi(argv[1]);
const int consumerT = std::stoi(argv[2]);
int threadSize = producerT + consumerT;
pthread_t threads[threadSize];
void *status;
Buffer b1;
Producer p(b1);
Consumer c(b1);
for (int i = 0; i < producerT; i++) {
pthread_create(&threads[i], NULL, &Producer::run, &p);
}
for (int i = producerT; i < threadSize; i++) {
pthread_create(&threads[i], NULL, &Consumer::run, &c);
}
sleeps(5000);
for (int i = 0; i < threadSize; i++) {
pthread_join(threads[i], &status);
}
exit(0);
}
You are probably looking for something like this:
class Producer {
static void static_run(void* pThis) {
static_cast<Producer*>(pThis)->run();
}
void run() {
// Real work done here.
}
};
// At call site
Producer p;
pthread_create(&threads[i], NULL, Producer::static_run, &p);
The point is that pthread_create wants a C-style function - either a standalone non-member function, or a static member function. So you need an adapter (sometimes referred to as a "trampoline") that satisfies the requirements, and then turns around and calls the member function.

thread pool in constructor of C++ class is getting killed

I have the following code which is creating thread pool in the constructor of the class. Threads got created and exited immediately.
Please help.
class ThreadPool {
public:
boost::asio::io_service io_service;
boost::thread_group threads;
ThreadPool();
void call();
void calling();
};
ThreadPool::ThreadPool() {
/* Create thread-pool now */
size_t numThreads = boost::thread::hardware_concurrency();
boost::asio::io_service::work work(io_service);
for(size_t t = 0; t < numThreads; t++) {
threads.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
}
}
void ThreadPool::call() {
std::cout << "Hi i'm thread no " << boost::this_thread::get_id() << std::endl;
};
void ThreadPool::calling() {
sleep(1);
io_service.post(boost::bind(&ThreadPool::call, this));
}
int main(int argc, char **argv)
{
ThreadPool pool;
for (int i = 0; i < 5; i++) {
pool.calling();
}
pool.threads.join_all();
return 0;
}
boost::asio::io_service::work work must be a member of the class, so it does not get destroyed.
class ThreadPool {
public:
boost::asio::io_service io_service;
boost::thread_group threads;
boost::asio::io_service::work *work;
ThreadPool();
void call();
void calling();
void stop() { delete work; }
};
ThreadPool::ThreadPool() : work(new boost::asio::io_service::work(io_service)) {
/* Create thread-pool now */
size_t numThreads = boost::thread::hardware_concurrency();
for(size_t t = 0; t < numThreads; t++) {
threads.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
}
}
void ThreadPool::call() {
std::cout << "Hi i'm thread no " << boost::this_thread::get_id() << std::endl;
};
void ThreadPool::calling() {
Sleep(1000);
io_service.post(boost::bind(&ThreadPool::call, this));
}
int main()
{
ThreadPool pool;
for (int i = 0; i < 5; i++) {
pool.calling();
}
pool.stop();
pool.threads.join_all();
return 0;
}

Sync object to wait without blocking UI in C++ (C++ Builder)

I have a task on multi-threading in C++ in which there is a critical code block. Main requirements are the followings:
the critical code can be allowed to be re-entered (by the same or another thread) only after its current execution is finished,
UI thread mustn't be frozen while it is waiting for another thread currently executing the critical code.
So I created the following class in C++ Builder to fulfill the requirements.
Do you think there is any issue in it?
Many thanks for your time in advance!
Class declaration / definition:
#include "windows.h"
#include <vector>
#include <algorithm>
class TSyncObject
{
private:
DWORD WorkingThreadId;
std::vector<DWORD> WaitingThreadIds;
TCriticalSection *Section;
HANDLE Event;
//---------------------------------------------------------------------------
bool CanThreadWait(const DWORD ThreadId)
{
bool CanWait;
Section->Enter();
try
{
bool AlreadyWaiting =
std::find(WaitingThreadIds.begin(), WaitingThreadIds.end(), ThreadId) != WaitingThreadIds.end();
CanWait = !AlreadyWaiting && ThreadId != WorkingThreadId && WorkingThreadId;
if (CanWait)
{
WaitingThreadIds.push_back(ThreadId);
}
}
__finally
{
Section->Leave();
}
return CanWait;
}
//---------------------------------------------------------------------------
void Acquire(const DWORD ThreadId)
{
Section->Enter();
try
{
WorkingThreadId = ThreadId;
std::vector<DWORD>::iterator Pos =
std::find(WaitingThreadIds.begin(), WaitingThreadIds.end(), ThreadId);
if (Pos != WaitingThreadIds.end())
{
WaitingThreadIds.erase(Pos);
}
}
__finally
{
Section->Leave();
}
}
//---------------------------------------------------------------------------
void HandleError()
{
Section->Enter();
try
{
if (GetCurrentThreadId() == WorkingThreadId ||
(WaitingThreadIds.empty() && !WorkingThreadId))
{
WorkingThreadId = 0;
SetEvent(Event);
}
}
__finally
{
Section->Leave();
}
}
//---------------------------------------------------------------------------
public:
//---------------------------------------------------------------------------
enum TThreadAcquire {Acquired, WaitEjected, AppTerminated, Failed};
//---------------------------------------------------------------------------
TSyncObject() :
WorkingThreadId(0),
Section(new TCriticalSection()),
Event(CreateEventW(0, 0, 1, 0))
{
}
//---------------------------------------------------------------------------
virtual ~TSyncObject()
{
CloseHandle(Event);
delete Section;
}
//---------------------------------------------------------------------------
TThreadAcquire Acquire()
{
try
{
DWORD CurrentThreadId = GetCurrentThreadId();
if (WaitForSingleObject(Event, 0) != WAIT_OBJECT_0)
{
if (!CanThreadWait(CurrentThreadId))
{
return WaitEjected;
}
while (!Application->Terminated &&
(MsgWaitForMultipleObjects(1, &Event, 0, INFINITE, QS_ALLINPUT) - WAIT_OBJECT_0))
{
Application->ProcessMessages();
}
if (Application->Terminated)
{
return AppTerminated;
}
}
Acquire(CurrentThreadId);
return Acquired;
}
catch (...)
{
HandleError();
return Failed;
}
}
//---------------------------------------------------------------------------
void Release()
{
Section->Enter();
try
{
WorkingThreadId = 0;
SetEvent(Event);
}
__finally
{
Section->Leave();
}
}
//---------------------------------------------------------------------------
};
I will use it like this:
TSyncObject Sync; // Global for all threads
//...
A thread uses the object like this:
TSyncObject::TThreadAcquire Acq = Sync.Acquire();
try
{
if (Acq == TSyncObject::WaitEjected)
{
//...
return;
}
else if (Acq == TSyncObject::AppTerminated)
{
//...
return;
}
else if (Acq == TSyncObject::Failed)
{
//...
return;
}
// critical code block
}
__finally
{
Sync.Release();
}
I would suggest replacing all of the event and criticalsection handling with a simple semaphore instead.
Try something more like this:
MySyncObject.hpp
#ifndef MySyncObjectH
#define MySyncObjectH
#include "windows.h"
class TSyncObject
{
private:
HANDLE Semaphore;
public:
enum TThreadAcquire {Acquired, WaitEjected, AppTerminated, Failed};
TSyncObject();
~TSyncObject();
TThreadAcquire Acquire();
void Release();
};
#endif
MySyncObject.cpp
#include "MySyncObject.hpp"
bool __thread SyncState = 0;
TSyncObject::TSyncObject()
: Semaphore(NULL)
{
Semaphore = CreateSemaphore(NULL, 1, 1, NULL);
if (!Semaphore) RaiseLastOSError();
}
TSyncObject::~TSyncObject()
{
CloseHandle(Semaphore);
}
TSyncObject::TThreadAcquire TSyncObject::Acquire()
{
DWORD dwRet = WaitForSingleObject(Semaphore, 0);
if (dwRet == WAIT_TIMEOUT)
{
if (SyncState != 0)
return WaitEjected;
SyncState = 1;
while (!Application->Terminated)
{
dwRet = MsgWaitForMultipleObjects(1, &Semaphore, FALSE, INFINITE, QS_ALLINPUT);
if ((dwRet == WAIT_OBJECT_0) || (dwRet == WAIT_FAILED))
break;
if (dwRet == (WAIT_OBJECT_0+1))
{
try
{
Application->ProcessMessages();
}
catch (...)
{
//...
}
}
}
}
if (dwRet != WAIT_OBJECT_0)
{
SyncState = 0;
if (Application->Terminated)
return AppTerminated;
return Failed;
}
SyncState = 2;
return Acquired;
}
void TSyncObject::Release()
{
ReleaseSemaphore(Semaphore, 1, NULL);
SyncState = 0;
}
Then use it like this:
TSyncObject Sync;
...
TSyncObject::TThreadAcquire Acq = Sync.Acquire();
if (Acq == TSyncObject::Acquired)
{
try
{
// critical code block...
}
__finally
{
Sync.Release();
}
}
else
{
if (Acq == TSyncObject::WaitEjected)
{
//...
}
else if (Acq == TSyncObject::AppTerminated)
{
//...
}
else // TSyncObject::Failed
{
//...
}
return;
}
With that said, you might consider writing the class as a singleton instead of declaring a global variable:
MySyncObject.hpp
#ifndef MySyncObjectH
#define MySyncObjectH
#include "windows.h"
class TSyncObject
{
private:
HANDLE Semaphore;
TSyncObject();
public:
enum TThreadAcquire {Acquired, WaitEjected, AppTerminated, Failed};
~TSyncObject();
static TSyncObject& Instance();
TThreadAcquire Acquire();
void Release();
};
#endif
MySyncObject.cpp
#include "MySyncObject.hpp"
...
static TSyncObject& TSyncObject::Instance()
{
static TSyncObject inst;
return inst;
}
...
TSyncObject::TThreadAcquire Acq = TSyncObject::Instance().Acquire();
if (Acq == TSyncObject::Acquired)
{
try
{
// critical code block...
}
__finally
{
TSyncObject::Instance().Release();
}
}
else
{
if (Acq == TSyncObject::WaitEjected)
{
//...
}
else if (Acq == TSyncObject::AppTerminated)
{
//...
}
else // TSyncObject::Failed
{
//...
}
return;
}
Alternatively:
MySyncObject.hpp
#ifndef MySyncObjectH
#define MySyncObjectH
#include "windows.h"
class TSyncObject
{
private:
HANDLE Semaphore;
TSyncObject();
static TSyncObject& Instance();
public:
enum TThreadAcquire {Acquired, WaitEjected, AppTerminated, Failed};
~TSyncObject();
static TThreadAcquire Acquire();
static void Release();
};
#endif
MySyncObject.cpp
#include "MySyncObject.hpp"
...
TSyncObject::TThreadAcquire TSyncObject::Acquire()
{
TSyncObject &inst = Instance();
// use inst.Semaphore as needed...
}
void TSyncObject::Release()
{
TSyncObject &inst = Instance();
// use inst.Semaphore as needed...
}
TSyncObject::TThreadAcquire Acq = TSyncObject::Acquire();
if (Acq == TSyncObject::Acquired)
{
try
{
// critical code block...
}
__finally
{
TSyncObject::Release();
}
}
else
{
if (Acq == TSyncObject::WaitEjected)
{
//...
}
else if (Acq == TSyncObject::AppTerminated)
{
//...
}
else // TSyncObject::Failed
{
//...
}
return;
}

How to prevent the usage of the same object on compile time?

I have wrote the small timer using pthreads. The code is rather simple
#include <cassert>
#include <ctime>
#include <iostream>
#include <limits>
#include <pthread.h>
#include <stdio.h>
#include <string>
class timer
{
public:
timer(const std::clock_t sec): m_sec(sec) {}
void set_time(const std::clock_t sec)
{
m_sec = sec;
}
void start()
{
_start_time = std::clock();
}
void restart()
{
_start_time = std::clock();
}
bool tick()
{
for(double elpsd = elapsed(); elpsd <= m_sec; elpsd = elapsed())
{
if(elpsd <= m_sec) {}
}
return true;
}
double elapsed() const
{
return double(std::clock() - _start_time) / CLOCKS_PER_SEC;
}
double elapsed_max() const
{
return (double((std::numeric_limits<std::clock_t>::max)()) - double(_start_time)) / double(CLOCKS_PER_SEC);
}
double elapsed_min() const
{
return double(1)/double(CLOCKS_PER_SEC);
}
private:
std::clock_t _start_time;
std::clock_t m_sec;
};
class worker
{
public:
void operator ()()
{
start();
}
virtual void start() = 0;
virtual ~worker() = 0;
};
inline worker::~worker()
{
}
class some_worker : public worker
{
std::string msg;
public:
some_worker(std::string p_msg) :
msg(p_msg)
{
}
~some_worker(){}
void start()
{
std::cout << msg << std::endl;
}
};
class timer_handler
{
worker* work;
pthread_t id;
pthread_attr_t attr;
timer* m_timer;
public:
timer_handler(const timer* const tm, const worker* const p_work)
{
assert(p_work != 0);
work = const_cast<worker*>(p_work);
pthread_attr_init(&attr);
assert(tm != 0);
m_timer = const_cast<timer*>(tm);
}
void start()
{
pthread_create(&id, &attr, (void* (*)(void*))&run, this);
}
static void run(timer_handler *working_class)
{
working_class->m_timer->start();
while(1) {
if(working_class->m_timer->tick()) {
working_class->work->operator()();
working_class->m_timer->restart();
}
}
}
int join()
{
return pthread_join(id, NULL);
}
~timer_handler()
{
pthread_attr_destroy(&attr);
delete work;
delete m_timer;
}
};
int main(int argc, char *argv[])
{
some_worker* wrk = new some_worker("Worker no: 1");
some_worker* wrk_2 = new some_worker("Worker no: 2");
timer* tm = new timer(1);
timer_handler* handler = new timer_handler(tm, wrk);
timer_handler* handler_2 = new timer_handler(tm, wrk_2);
handler->start();
handler_2->start();
handler->join();
handler_2->join();
return 0;
}
But the in the main() these two handlers are use the same timer and it can be the cause of problem, because f.e. one thread can call timer->start(), another can call restart() and etc. The question is how to prevent the usage of the same object on compile time instead of using mutex which can be useful only on run-time.