PThreadWrappers return with the retval of called pthread. Task became an interface. WorkerThread moved to test_ThreadPool.hpp. Thread has stop() and m_isRunning members. ThreadPool is now Task and Thread type independent. No more assertions in PThreadWrappers. Unittests refactored. test dir cleaned up.
parent
123b9fca17
commit
01cde4928d
@ -1,26 +0,0 @@
|
|||||||
#ifndef WORKER_THREAD_HPP
|
|
||||||
#define WORKER_THREAD_HPP
|
|
||||||
|
|
||||||
#include "Thread.hpp"
|
|
||||||
#include "ThreadPool.hpp"
|
|
||||||
|
|
||||||
class ThreadPool;
|
|
||||||
|
|
||||||
class WorkerThread : public Thread
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
WorkerThread( ThreadPool& tp );
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void* run();
|
|
||||||
|
|
||||||
ThreadPool& m_tp;
|
|
||||||
bool m_isRunning;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // WORKER_THREAD_HPP
|
|
@ -1,30 +0,0 @@
|
|||||||
#include "Task.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "Common.hpp"
|
|
||||||
|
|
||||||
Task::Task() : m_timeOut(5)
|
|
||||||
{
|
|
||||||
TRACE(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Task::run()
|
|
||||||
{
|
|
||||||
TRACE(this);
|
|
||||||
m_startedToRun = time(NULL);
|
|
||||||
|
|
||||||
std::cout << "I'm a task..." << std::endl;
|
|
||||||
|
|
||||||
// other stuff
|
|
||||||
|
|
||||||
m_startedToRun = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Task::isItStucked () const
|
|
||||||
{
|
|
||||||
TRACE(this);
|
|
||||||
return ( m_startedToRun + m_timeOut < time(NULL) );
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
#include "WorkerThread.hpp"
|
|
||||||
#include "Task.hpp"
|
|
||||||
#include "Common.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
WorkerThread::WorkerThread( ThreadPool& tp )
|
|
||||||
: m_tp(tp)
|
|
||||||
, m_isRunning(true)
|
|
||||||
{
|
|
||||||
TRACE(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void WorkerThread::stop()
|
|
||||||
{
|
|
||||||
TRACE(this);
|
|
||||||
m_isRunning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void* WorkerThread::run()
|
|
||||||
{
|
|
||||||
TRACE(this);
|
|
||||||
while ( m_isRunning )
|
|
||||||
{
|
|
||||||
Task* task(0);
|
|
||||||
try {
|
|
||||||
task = m_tp.popTask();
|
|
||||||
task->run();
|
|
||||||
delete task;
|
|
||||||
} catch (CancelledException) {
|
|
||||||
std::cout << "Now I die." << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
|||||||
// g++ -Wall -Wextra src/*.cpp test/main_Mutex.cpp -Iinclude -lpthread -lrt
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include "Mutex.hpp"
|
|
||||||
|
|
||||||
Mutex m;
|
|
||||||
int counter = 0;
|
|
||||||
|
|
||||||
void *functionC( void* params )
|
|
||||||
{
|
|
||||||
m.lock();
|
|
||||||
counter++;
|
|
||||||
std::cout << "Counter value: " << counter << std::endl;
|
|
||||||
m.unlock();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
pthread_t thread1, thread2;
|
|
||||||
|
|
||||||
pthread_create( &thread1, 0, &functionC, 0 );
|
|
||||||
pthread_create( &thread2, 0, &functionC, 0 );
|
|
||||||
|
|
||||||
pthread_join( thread1, 0 );
|
|
||||||
pthread_join( thread2, 0 );
|
|
||||||
|
|
||||||
Mutex m2(PTHREAD_MUTEX_ERRORCHECK);
|
|
||||||
|
|
||||||
m2.lock();
|
|
||||||
m2.unlock();
|
|
||||||
|
|
||||||
m2.unlock();
|
|
||||||
m2.unlock();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
|||||||
// g++ -Wall -Wextra src/*.cpp test/main_Mutex.cpp -Iinclude -lpthread -lrt
|
|
||||||
|
|
||||||
|
|
||||||
#include "ScopedLock.hpp"
|
|
||||||
#include "Mutex.hpp"
|
|
||||||
#include "Common.hpp"
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
class User
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
User() : m_mutex() {
|
|
||||||
TRACE(this);
|
|
||||||
}
|
|
||||||
~User() {
|
|
||||||
TRACE(this);
|
|
||||||
}
|
|
||||||
void fv() {
|
|
||||||
TRACE(this);
|
|
||||||
ScopedLock sl(&m_mutex);
|
|
||||||
throw std::logic_error("whoops");
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
Mutex m_mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
User u;
|
|
||||||
|
|
||||||
try {
|
|
||||||
u.fv();
|
|
||||||
} catch (std::logic_error ex) {
|
|
||||||
std::cout << "std::logicexception: " << ex.what() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "../ConcurrentQueue.hpp"
|
|
||||||
#include "../Thread.hpp"
|
|
||||||
|
|
||||||
#define TRACE std::cout << __FILE__ << " @ " << __PRETTY_FUNCTION__ << ":" << __LINE__ << std::endl;
|
|
||||||
|
|
||||||
class WaitingThread : public Thread
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
WaitingThread (ConcurrentQueue<int>& cq)
|
|
||||||
: m_isRunning( true ),
|
|
||||||
m_cq(cq)
|
|
||||||
{
|
|
||||||
TRACE
|
|
||||||
}
|
|
||||||
|
|
||||||
~WaitingThread()
|
|
||||||
{
|
|
||||||
TRACE
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop ()
|
|
||||||
{
|
|
||||||
TRACE
|
|
||||||
m_isRunning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void* run ()
|
|
||||||
{
|
|
||||||
TRACE
|
|
||||||
while ( m_isRunning )
|
|
||||||
{
|
|
||||||
std::cout << "waiting..." << std::endl;
|
|
||||||
int retval = m_cq.waitAndPop();
|
|
||||||
std::cout << "waiting...ENDED! Got retval: " << retval << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool m_isRunning;
|
|
||||||
ConcurrentQueue<int>& m_cq;
|
|
||||||
};
|
|
||||||
|
|
||||||
class fake_type
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
fake_type(int i) : m_int(i)
|
|
||||||
{
|
|
||||||
TRACE
|
|
||||||
}
|
|
||||||
|
|
||||||
~fake_type()
|
|
||||||
{
|
|
||||||
TRACE
|
|
||||||
}
|
|
||||||
|
|
||||||
fake_type( const fake_type& m)
|
|
||||||
{
|
|
||||||
TRACE
|
|
||||||
m_int = m.m_int;
|
|
||||||
}
|
|
||||||
|
|
||||||
fake_type& operator=( const fake_type& m)
|
|
||||||
{
|
|
||||||
TRACE
|
|
||||||
m_int = m.m_int;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int m_int;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
ConcurrentQueue<fake_type> cq1;
|
|
||||||
cq1.push(fake_type(7));
|
|
||||||
|
|
||||||
fake_type m = cq1.waitAndPop();
|
|
||||||
|
|
||||||
// other case
|
|
||||||
|
|
||||||
ConcurrentQueue<int> cq2;
|
|
||||||
cq2.push(7);
|
|
||||||
cq2.push(13);
|
|
||||||
|
|
||||||
WaitingThread* wt1 = new WaitingThread(cq2);
|
|
||||||
wt1->start();
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
|
|
||||||
cq2.push(34);
|
|
||||||
|
|
||||||
sleep(5);
|
|
||||||
|
|
||||||
wt1->stop();
|
|
||||||
|
|
||||||
sleep(5);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
pthread_mutex_t p_mutex;
|
|
||||||
|
|
||||||
// #include <boost/thread/mutex.hpp>
|
|
||||||
// boost::mutex b_mutex;
|
|
||||||
|
|
||||||
#define TRACE std::cout << __FILE__ << " @ " << __PRETTY_FUNCTION__ << ":" << __LINE__ << std::endl;
|
|
||||||
|
|
||||||
|
|
||||||
class ScopedLock
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
ScopedLock(pthread_mutex_t & mutex) : m_mutex(mutex)
|
|
||||||
{
|
|
||||||
TRACE;
|
|
||||||
pthread_mutex_lock( &m_mutex );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
~ScopedLock(void )
|
|
||||||
{
|
|
||||||
TRACE;
|
|
||||||
pthread_mutex_unlock( &m_mutex );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
pthread_mutex_t& m_mutex;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void fv ()
|
|
||||||
{
|
|
||||||
ScopedLock sl(p_mutex);
|
|
||||||
|
|
||||||
throw std::logic_error("p_thread stuff");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// void fv2 ()
|
|
||||||
// {
|
|
||||||
// boost::mutex::scoped_lock lock(&b_mutex);
|
|
||||||
//
|
|
||||||
// throw std::logic_error("boost_thread stuff");
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
pthread_mutex_init( &p_mutex, NULL );
|
|
||||||
try {
|
|
||||||
fv();
|
|
||||||
} catch (...) {
|
|
||||||
TRACE;
|
|
||||||
|
|
||||||
if (pthread_mutex_trylock( &p_mutex) == 0 ) {
|
|
||||||
// std::cout << "pthread mutex is OK, unlocked " << std::endl;
|
|
||||||
// pthread_mutex_unlock( &p_mutex );
|
|
||||||
} else {
|
|
||||||
// std::cout << "pthread mutex is STILL LOCKED!" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pthread_mutex_destroy( &p_mutex );
|
|
||||||
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// fv2();
|
|
||||||
// } catch (...) {
|
|
||||||
// TRACE;
|
|
||||||
// if ( b_mutex.try_lock() == true ) {
|
|
||||||
// std::cout << "boost mutex is OK, unlocked " << std::endl;
|
|
||||||
// b_mutex.unlock();
|
|
||||||
// } else {
|
|
||||||
// std::cout << "boost mutex is STILL LOCKED!" << std::endl;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,206 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
|
|
||||||
#ifndef NOTRACE
|
|
||||||
#define TRACE(x) std::cout << x << " " << __PRETTY_FUNCTION__ << \
|
|
||||||
" : " << __LINE__ << std::endl
|
|
||||||
|
|
||||||
#else
|
|
||||||
/// @todo Get rid of the "warning: statement has no effect" compiler msgs
|
|
||||||
#define TRACE(x) ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
class Mutex
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
Mutex() {
|
|
||||||
TRACE(this);
|
|
||||||
int ret = pthread_mutex_init( &m_mutex, 0 );
|
|
||||||
// assert( ret == 0 );
|
|
||||||
}
|
|
||||||
~Mutex() {
|
|
||||||
TRACE(this);
|
|
||||||
int ret = pthread_mutex_destroy ( &m_mutex );
|
|
||||||
// assert( ret == 0 );
|
|
||||||
}
|
|
||||||
void lock() {
|
|
||||||
TRACE(this);
|
|
||||||
int ret = pthread_mutex_lock( &m_mutex );
|
|
||||||
// assert( ret == 0 );
|
|
||||||
}
|
|
||||||
void unlock() {
|
|
||||||
TRACE(this);
|
|
||||||
int ret = pthread_mutex_unlock( &m_mutex );
|
|
||||||
// assert( ret == 0 );
|
|
||||||
}
|
|
||||||
// private:
|
|
||||||
Mutex(const Mutex& m){
|
|
||||||
TRACE(this);
|
|
||||||
}
|
|
||||||
Mutex& operator=(const Mutex& m) {
|
|
||||||
TRACE(this);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tryLock() {
|
|
||||||
TRACE(this);
|
|
||||||
// return pthread_mutex_trylock(&m_mutex);
|
|
||||||
int interval = 1;
|
|
||||||
|
|
||||||
timespec abs_time;
|
|
||||||
clock_gettime ( CLOCK_REALTIME, &abs_time );
|
|
||||||
abs_time.tv_nsec += interval * 1000000;
|
|
||||||
if ( abs_time.tv_nsec >= 1000000000 ) {
|
|
||||||
abs_time.tv_nsec -= 1000000000;
|
|
||||||
abs_time.tv_sec += 1;
|
|
||||||
}
|
|
||||||
return pthread_mutex_timedlock ( &m_mutex, &abs_time );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
pthread_mutex_t m_mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class BadScopedLock
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
BadScopedLock(Mutex& m)
|
|
||||||
: m_mutex(m) /// @note cctor called!
|
|
||||||
{
|
|
||||||
TRACE(this);
|
|
||||||
m_mutex.lock();
|
|
||||||
}
|
|
||||||
~BadScopedLock() {
|
|
||||||
TRACE(this);
|
|
||||||
m_mutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BadScopedLock(const BadScopedLock&);
|
|
||||||
BadScopedLock& operator=(const BadScopedLock&);
|
|
||||||
|
|
||||||
Mutex& m_mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
class UnluckyUser
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
UnluckyUser() : m_mutex() {
|
|
||||||
TRACE(this);
|
|
||||||
}
|
|
||||||
~UnluckyUser() {
|
|
||||||
TRACE(this);
|
|
||||||
}
|
|
||||||
void fv() {
|
|
||||||
TRACE(this);
|
|
||||||
BadScopedLock sl(m_mutex);
|
|
||||||
throw std::logic_error("whoops");
|
|
||||||
}
|
|
||||||
int tryLock() {
|
|
||||||
TRACE(this);
|
|
||||||
return m_mutex.tryLock();
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
Mutex m_mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
// class GoodScopedLock
|
|
||||||
// {
|
|
||||||
// public:
|
|
||||||
//
|
|
||||||
// GoodScopedLock(Mutex* m) : m_mutex(m)
|
|
||||||
// {
|
|
||||||
// TRACE(this);
|
|
||||||
// m_mutex->lock();
|
|
||||||
// }
|
|
||||||
// ~GoodScopedLock() {
|
|
||||||
// TRACE(this);
|
|
||||||
// m_mutex->unlock();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private:
|
|
||||||
// GoodScopedLock(const GoodScopedLock&);
|
|
||||||
// GoodScopedLock& operator=(const GoodScopedLock&);
|
|
||||||
//
|
|
||||||
// Mutex* m_mutex;
|
|
||||||
// };
|
|
||||||
/*
|
|
||||||
class LuckyUser
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LuckyUser() : m_mutex() {
|
|
||||||
TRACE(this);
|
|
||||||
}
|
|
||||||
~LuckyUser() {
|
|
||||||
TRACE(this);
|
|
||||||
}
|
|
||||||
void fv() {
|
|
||||||
TRACE(this);
|
|
||||||
GoodScopedLock sl(&m_mutex);
|
|
||||||
throw std::logic_error("whoops");
|
|
||||||
}
|
|
||||||
int tryLock() {
|
|
||||||
TRACE(this);
|
|
||||||
return m_mutex.tryLock();
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
Mutex m_mutex;
|
|
||||||
};*/
|
|
||||||
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
TRACE("main begin");
|
|
||||||
// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
// // pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
|
|
||||||
// std::cout << "bla1" << std::endl;
|
|
||||||
// std::cout << pthread_mutex_unlock( &mutex )<< std::endl;
|
|
||||||
// std::cout << pthread_mutex_trylock( &mutex ) << std::endl;
|
|
||||||
// std::cout << "bla2" << std::endl;
|
|
||||||
// // std::cout << pthread_mutex_unlock( &mutex ) << std::endl;
|
|
||||||
//
|
|
||||||
// std::cout << "bla3" << std::endl;
|
|
||||||
//
|
|
||||||
// std::cout << pthread_mutex_lock( &mutex ) << std::endl;
|
|
||||||
// std::cout << pthread_mutex_trylock( &mutex ) << std::endl;
|
|
||||||
// // std::cout << pthread_mutex_lock( &mutex ) << std::endl;
|
|
||||||
|
|
||||||
UnluckyUser u;
|
|
||||||
try {
|
|
||||||
u.fv();
|
|
||||||
} catch (std::logic_error ex) {
|
|
||||||
std::cout << "std::logicexception: " << ex.what() << std::endl;
|
|
||||||
if (u.tryLock() == 0) {
|
|
||||||
std::cout << "UnluckyUser: Ok, mutex is unlocked" << std::endl;
|
|
||||||
} else {
|
|
||||||
std::cout << "UnluckyUser: Failed, mutex is still locked" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TRACE("main middle");
|
|
||||||
//
|
|
||||||
// LuckyUser u2;
|
|
||||||
// try {
|
|
||||||
// u2.fv();
|
|
||||||
// } catch (std::logic_error ex) {
|
|
||||||
// std::cout << "std::logicexception: " << ex.what() << std::endl;
|
|
||||||
// if (u2.tryLock() == 0) {
|
|
||||||
// std::cout << "LuckyUser: Ok, mutex is unlocked" << std::endl;
|
|
||||||
// } else {
|
|
||||||
// std::cout << "LuckyUser: Failed, mutex is still locked" << std::endl;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
TRACE("main end");
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <signal.h> // signal to thread
|
|
||||||
#include <stdlib.h> // malloc
|
|
||||||
// #include <string.h>
|
|
||||||
|
|
||||||
#include "Thread.hpp"
|
|
||||||
#include "Common.hpp"
|
|
||||||
|
|
||||||
class ThreadClass : public Thread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
~ThreadClass() { TRACE(this); }
|
|
||||||
ThreadClass() { TRACE(this); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void* run( void ) {
|
|
||||||
TRACE(this);
|
|
||||||
|
|
||||||
void *retval = malloc(sizeof(int));
|
|
||||||
*((int*)retval) = 14;
|
|
||||||
return retval;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ThreadClassWithSignal : public Thread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
~ThreadClassWithSignal() {
|
|
||||||
TRACE(this);
|
|
||||||
}
|
|
||||||
ThreadClassWithSignal() {
|
|
||||||
TRACE(this);
|
|
||||||
signal(SIGINT, signal_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void* run( void ) {
|
|
||||||
TRACE(this);
|
|
||||||
|
|
||||||
void *retval = malloc(sizeof(int));
|
|
||||||
*((int*)retval) = 14;
|
|
||||||
return retval;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void static signal_handler(int sig)
|
|
||||||
{
|
|
||||||
TRACE("ThreadClassWithSignal::signal_handler");
|
|
||||||
if (sig==SIGINT) {
|
|
||||||
TRACE("signal_handler got SIGINT");
|
|
||||||
pthread_exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
TRACE("main start");
|
|
||||||
|
|
||||||
ThreadClass *m = new ThreadClass;
|
|
||||||
m->start();
|
|
||||||
|
|
||||||
void *retVal = m->join();
|
|
||||||
std::cout << "got retVal: " << *((int*)retVal) << std::endl;
|
|
||||||
free(retVal);
|
|
||||||
delete m;
|
|
||||||
|
|
||||||
ThreadClass *m2 = new ThreadClass;
|
|
||||||
m2->start();
|
|
||||||
m2->sendSignal(SIGINT);
|
|
||||||
|
|
||||||
sleep(3);
|
|
||||||
|
|
||||||
std::cout << "after sendSignal the:" << m2 <<std::endl;
|
|
||||||
delete m2;
|
|
||||||
|
|
||||||
|
|
||||||
TRACE("main end");
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "ThreadPool.hpp"
|
|
||||||
#include "Task.hpp"
|
|
||||||
#include "Common.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
TRACE("Main start");
|
|
||||||
|
|
||||||
ThreadPool* tp = new ThreadPool(5);
|
|
||||||
tp->startWorkerThreads();
|
|
||||||
|
|
||||||
Task* t1 = new Task();
|
|
||||||
tp->pushTask(t1);
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
|
|
||||||
tp->stop();
|
|
||||||
tp->join();
|
|
||||||
delete tp;
|
|
||||||
|
|
||||||
TRACE("Main end");
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -0,0 +1,19 @@
|
|||||||
|
#include <cxxtest/TestSuite.h>
|
||||||
|
|
||||||
|
#include "Mutex.hpp"
|
||||||
|
#include "ConditionVariable.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
class TestConditionVariable : public CxxTest::TestSuite
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void testBasic( void )
|
||||||
|
{
|
||||||
|
Mutex m;
|
||||||
|
ConditionVariable c(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
@ -0,0 +1,47 @@
|
|||||||
|
#include <cxxtest/TestSuite.h>
|
||||||
|
|
||||||
|
#include "Common.hpp"
|
||||||
|
#include "Mutex.hpp"
|
||||||
|
|
||||||
|
#include <errno.h> // EDEADLK, EPERM
|
||||||
|
|
||||||
|
class TestMutex : public CxxTest::TestSuite
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void testBasic( void )
|
||||||
|
{
|
||||||
|
Mutex m;
|
||||||
|
TS_ASSERT_EQUALS ( m.lock() , 0 );
|
||||||
|
// TS_ASSERT_EQUALS ( m.lock() , 0 ); that would be a deadlock
|
||||||
|
TS_ASSERT_EQUALS ( m.tryLock(0), false );
|
||||||
|
TS_ASSERT_EQUALS ( m.tryLock(2), false );
|
||||||
|
TS_ASSERT_EQUALS ( m.unlock() , 0 );
|
||||||
|
TS_ASSERT_EQUALS ( m.unlock() , 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void testErrorCheck( void )
|
||||||
|
{
|
||||||
|
Mutex m(PTHREAD_MUTEX_ERRORCHECK);
|
||||||
|
TS_ASSERT_EQUALS ( m.lock() , 0 );
|
||||||
|
TS_ASSERT_EQUALS ( m.lock(), EDEADLK );
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS ( m.unlock() , 0 );
|
||||||
|
TS_ASSERT_EQUALS ( m.unlock() , EPERM );
|
||||||
|
}
|
||||||
|
|
||||||
|
void testRecursive( void )
|
||||||
|
{
|
||||||
|
Mutex m(PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
TS_ASSERT_EQUALS ( m.lock() , 0 );
|
||||||
|
TS_ASSERT_EQUALS ( m.lock() , 0 );
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS ( m.unlock() , 0 );
|
||||||
|
TS_ASSERT_EQUALS ( m.unlock() , 0 );
|
||||||
|
TS_ASSERT_EQUALS ( m.unlock() , EPERM );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
@ -0,0 +1,32 @@
|
|||||||
|
#include <cxxtest/TestSuite.h>
|
||||||
|
|
||||||
|
#define private public // need to reach private variables
|
||||||
|
|
||||||
|
#include "Common.hpp"
|
||||||
|
#include "Mutex.hpp"
|
||||||
|
|
||||||
|
class TestPThreadWrappers : public CxxTest::TestSuite
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void testMutexBasic( void )
|
||||||
|
{
|
||||||
|
Mutex m;
|
||||||
|
m.lock();
|
||||||
|
TS_ASSERT_EQUALS ( m.tryLock(0), 0 );
|
||||||
|
m.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void testMutexCreate( void )
|
||||||
|
{
|
||||||
|
Mutex m(PTHREAD_MUTEX_ERRORCHECK);
|
||||||
|
m.lock();
|
||||||
|
TS_ASSERT_EQUALS ( m.lock(), 1 );
|
||||||
|
|
||||||
|
m.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
@ -0,0 +1,23 @@
|
|||||||
|
#include <cxxtest/TestSuite.h>
|
||||||
|
|
||||||
|
#include "ScopedLock.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
class TestScopedLock : public CxxTest::TestSuite
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void testBasic( void )
|
||||||
|
{
|
||||||
|
Mutex m;
|
||||||
|
|
||||||
|
{
|
||||||
|
ScopedLock sl(m);
|
||||||
|
TS_ASSERT_EQUALS ( m.tryLock(0), false );
|
||||||
|
}
|
||||||
|
TS_ASSERT_EQUALS ( m.tryLock(0), true );
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
@ -0,0 +1,116 @@
|
|||||||
|
#include <cxxtest/TestSuite.h>
|
||||||
|
|
||||||
|
#include "Thread.hpp"
|
||||||
|
#include "Common.hpp"
|
||||||
|
#include "Mutex.hpp"
|
||||||
|
#include "ScopedLock.hpp"
|
||||||
|
|
||||||
|
#include <stdlib.h> // malloc
|
||||||
|
#include <signal.h> // SIGINT
|
||||||
|
|
||||||
|
|
||||||
|
class TestThread : public CxxTest::TestSuite
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
class ThreadClass : public Thread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ThreadClass() { TRACE(this); }
|
||||||
|
~ThreadClass() { TRACE(this); }
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
ThreadClass(const ThreadClass&) { TRACE(this); }
|
||||||
|
ThreadClass& operator=(const ThreadClass&) { TRACE(this); return*this; }
|
||||||
|
|
||||||
|
void* run( void ) {
|
||||||
|
TRACE(this);
|
||||||
|
|
||||||
|
void* retVal = malloc(sizeof(int));
|
||||||
|
*((int*)retVal) = 14;
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void testBasic( void )
|
||||||
|
{
|
||||||
|
ThreadClass *m = new ThreadClass;
|
||||||
|
m->start();
|
||||||
|
|
||||||
|
void *retVal = m->join();
|
||||||
|
TS_ASSERT_EQUALS ( *((int*)retVal) , 14 );
|
||||||
|
free(retVal);
|
||||||
|
delete m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note send a signal to a thread
|
||||||
|
*/
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
class ThreadClassWithSignal : public Thread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ThreadClassWithSignal() {
|
||||||
|
TRACE(this);
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
}
|
||||||
|
~ThreadClassWithSignal() {
|
||||||
|
TRACE(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
ThreadClassWithSignal(const ThreadClassWithSignal&) { TRACE(this); }
|
||||||
|
ThreadClassWithSignal& operator=(const ThreadClassWithSignal&) { TRACE(this); return*this; }
|
||||||
|
|
||||||
|
void* run( void ) {
|
||||||
|
TRACE(this);
|
||||||
|
|
||||||
|
/** @note the function will get stopped before it finishes sleeping
|
||||||
|
* If signal arrives after malloc, it will be a memory leak.
|
||||||
|
*/
|
||||||
|
sleep(32);
|
||||||
|
|
||||||
|
void* retVal = malloc(sizeof(int));
|
||||||
|
*((int*)retVal) = 15;
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void signal_handler(int sig)
|
||||||
|
{
|
||||||
|
TRACE("ThreadClassWithSignal::signal_handler");
|
||||||
|
if (sig==SIGINT) {
|
||||||
|
TRACE("signal_handler got SIGINT");
|
||||||
|
|
||||||
|
void* retVal = malloc(sizeof(int));
|
||||||
|
*((int*)retVal) = 16;
|
||||||
|
pthread_exit(retVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void testSignalSend( void )
|
||||||
|
{
|
||||||
|
ThreadClassWithSignal *m2 = new ThreadClassWithSignal;
|
||||||
|
m2->start();
|
||||||
|
m2->sendSignal(SIGINT);
|
||||||
|
|
||||||
|
sleep(3);
|
||||||
|
void *retVal = m2->join();
|
||||||
|
TS_ASSERT_EQUALS ( *((int*)retVal) , 16 );
|
||||||
|
free(retVal);
|
||||||
|
delete m2;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
@ -0,0 +1,97 @@
|
|||||||
|
#include <cxxtest/TestSuite.h>
|
||||||
|
|
||||||
|
// #include <time.h> // time
|
||||||
|
|
||||||
|
#include "Task.hpp"
|
||||||
|
#include "Thread.hpp"
|
||||||
|
#include "ThreadPool.hpp"
|
||||||
|
#include "Common.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TestThreadPoolSuite : public CxxTest::TestSuite
|
||||||
|
{
|
||||||
|
|
||||||
|
class DummyTask : public Task
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DummyTask() { m_timeOut = 5; TRACE(this); }
|
||||||
|
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
TRACE(this);
|
||||||
|
m_startedToRun = time(NULL);
|
||||||
|
TRACE("I'm a task...");
|
||||||
|
m_startedToRun = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isItStucked () const
|
||||||
|
{
|
||||||
|
TRACE(this);
|
||||||
|
return ( m_startedToRun + m_timeOut < time(NULL) );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class WorkerThread : public Thread
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
WorkerThread( ThreadPool& tp )
|
||||||
|
: m_tp(tp)
|
||||||
|
{
|
||||||
|
TRACE(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void* run()
|
||||||
|
{
|
||||||
|
TRACE(this);
|
||||||
|
while ( m_isRunning )
|
||||||
|
{
|
||||||
|
Task* task(0);
|
||||||
|
try {
|
||||||
|
task = m_tp.popTask();
|
||||||
|
task->run();
|
||||||
|
delete task;
|
||||||
|
} catch (CancelledException) {
|
||||||
|
TRACE("Now I die.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadPool& m_tp;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void testBasic()
|
||||||
|
{
|
||||||
|
ThreadPool* tp = new ThreadPool();
|
||||||
|
|
||||||
|
Thread* wt1 = new WorkerThread(*tp);
|
||||||
|
Thread* wt2 = new WorkerThread(*tp);
|
||||||
|
Thread* wt3 = new WorkerThread(*tp);
|
||||||
|
tp->pushWorkerThread(wt1);
|
||||||
|
tp->pushWorkerThread(wt2);
|
||||||
|
tp->pushWorkerThread(wt3);
|
||||||
|
tp->startWorkerThreads();
|
||||||
|
|
||||||
|
Task* t1 = new DummyTask();
|
||||||
|
tp->pushTask(t1);
|
||||||
|
Task* t2 = new DummyTask();
|
||||||
|
tp->pushTask(t2);
|
||||||
|
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
tp->stop();
|
||||||
|
tp->join();
|
||||||
|
delete tp;
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in new issue