new classes: concurrentqueue, Task, Thread, ThreadPool, WorkerThread, and some tests. Trying to have cxxtest and cmake
parent
a39371125e
commit
dccd38d8e7
@ -0,0 +1,5 @@
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (CPP_UTILS_LIB)
|
||||
|
||||
add_subdirectory (build)
|
||||
add_subdirectory (test)
|
@ -0,0 +1,17 @@
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (CPP_UTILS_LIB)
|
||||
|
||||
message(STATUS "Lib dir:")
|
||||
|
||||
set (CXX_FLAGS "-Wall -Wextra -pedantic")
|
||||
add_definitions( ${CXX_FLAGS} )
|
||||
message(STATUS "g++ flags: ${CXX_FLAGS}")
|
||||
|
||||
include_directories (../include)
|
||||
message(STATUS "include dir: ${CPP_UTILS_LIB}/include")
|
||||
|
||||
aux_source_directory(../src CPP_UTILS_LIB_SOURCES)
|
||||
message(STATUS "sources: ${CPP_UTILS_LIB_SOURCES}")
|
||||
|
||||
add_library (CppUtils ${CPP_UTILS_LIB_SOURCES})
|
||||
target_link_libraries(CppUtils pthread rt)
|
@ -0,0 +1,103 @@
|
||||
#ifndef CONCURRENTQUEUE_HPP
|
||||
#define CONCURRENTQUEUE_HPP
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "Mutex.hpp"
|
||||
#include "ConditionVariable.hpp"
|
||||
#include "ScopedLock.hpp"
|
||||
#include "Common.hpp"
|
||||
|
||||
|
||||
|
||||
class CancelledException {};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class ConcurrentQueue {
|
||||
|
||||
public:
|
||||
|
||||
ConcurrentQueue()
|
||||
: m_cancelled(false)
|
||||
, m_mutex()
|
||||
, m_condition(&m_mutex)
|
||||
{
|
||||
TRACE(this);
|
||||
}
|
||||
|
||||
~ConcurrentQueue()
|
||||
{
|
||||
TRACE(this);
|
||||
}
|
||||
|
||||
|
||||
void push(const T task)
|
||||
{
|
||||
TRACE(this);
|
||||
ScopedLock sl(&m_mutex);
|
||||
if (m_cancelled) throw CancelledException();
|
||||
m_queue.push( task );
|
||||
m_condition.signal();
|
||||
}
|
||||
|
||||
|
||||
bool tryPop(T &popped_value)
|
||||
{
|
||||
TRACE(this);
|
||||
ScopedLock sl(&m_mutex);
|
||||
if (m_cancelled) throw CancelledException();
|
||||
if ( m_queue.empty() ) return false;
|
||||
|
||||
popped_value = m_queue.front();
|
||||
m_queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
T waitAndPop()
|
||||
{
|
||||
TRACE(this);
|
||||
ScopedLock sl(&m_mutex);
|
||||
|
||||
while ( m_queue.empty() and not m_cancelled) {
|
||||
m_condition.wait();
|
||||
}
|
||||
if (m_cancelled) throw CancelledException();
|
||||
|
||||
T retVal = m_queue.front(); // cctor
|
||||
m_queue.pop();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
TRACE(this);
|
||||
ScopedLock sl(&m_mutex);
|
||||
if (m_cancelled) throw CancelledException();
|
||||
return m_queue.empty();
|
||||
}
|
||||
|
||||
|
||||
void cancel()
|
||||
{
|
||||
TRACE(this);
|
||||
ScopedLock sl(&m_mutex);
|
||||
m_cancelled = true;
|
||||
m_condition.broadcast();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
ConcurrentQueue& operator=( const ConcurrentQueue& );
|
||||
ConcurrentQueue( const ConcurrentQueue& );
|
||||
|
||||
std::queue<T> m_queue;
|
||||
bool m_cancelled;
|
||||
Mutex m_mutex;
|
||||
ConditionVariable m_condition;
|
||||
|
||||
};
|
||||
|
||||
#endif // CONCURRENTQUEUE_HPP
|
@ -0,0 +1,55 @@
|
||||
#ifndef SINGLETON_HPP
|
||||
#define SINGLETON_HPP
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
template<typename T>
|
||||
class Singleton
|
||||
{
|
||||
protected:
|
||||
|
||||
Singleton() { TRACE("Simgleton::Singleton()"); }
|
||||
virtual ~Singleton() { TRACE("Simgleton::~Singleton()"); }
|
||||
|
||||
private:
|
||||
|
||||
Singleton( const Singleton& );
|
||||
Singleton& operator=( const Singleton& );
|
||||
|
||||
public:
|
||||
|
||||
static void createInstance()
|
||||
{
|
||||
TRACE("Simgleton::createInstance()");
|
||||
if ( m_instance ) {
|
||||
delete m_instance;
|
||||
}
|
||||
m_instance = new T();
|
||||
}
|
||||
|
||||
|
||||
static T* getInstance()
|
||||
{
|
||||
TRACE("Simgleton::getInstance()");
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
|
||||
static void destroy()
|
||||
{
|
||||
TRACE("Simgleton::destroy()");
|
||||
if ( m_instance ) {
|
||||
delete m_instance;
|
||||
}
|
||||
m_instance = 0;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
static T* m_instance;
|
||||
};
|
||||
|
||||
template<class T> T* Singleton<T>::m_instance = 0;
|
||||
|
||||
#endif // SINGLETON_HPP
|
@ -0,0 +1,25 @@
|
||||
#ifndef TASK_HPP
|
||||
#define TASK_HPP
|
||||
|
||||
#include <time.h>
|
||||
|
||||
class Task
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Task();
|
||||
|
||||
void run ();
|
||||
|
||||
bool isItStucked () const;
|
||||
|
||||
private:
|
||||
|
||||
time_t m_startedToRun;
|
||||
time_t m_timeOut;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // TASK_HPP
|
@ -0,0 +1,30 @@
|
||||
#ifndef THREAD_HPP
|
||||
#define THREAD_HPP
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
class Thread
|
||||
{
|
||||
public:
|
||||
|
||||
Thread();
|
||||
virtual ~Thread();
|
||||
|
||||
void start();
|
||||
void* join() const;
|
||||
void sendSignal( const int nSignal ) const;
|
||||
|
||||
private:
|
||||
|
||||
virtual void* run() = 0;
|
||||
static void* threadStarter( void* pData );
|
||||
|
||||
private:
|
||||
|
||||
pthread_t m_nThread;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // THREAD_HPP
|
@ -0,0 +1,42 @@
|
||||
#ifndef THREADPOOL_HPP
|
||||
#define THREADPOOL_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "ConcurrentQueue.hpp"
|
||||
#include "WorkerThread.hpp"
|
||||
#include "Task.hpp"
|
||||
#include "Mutex.hpp"
|
||||
|
||||
|
||||
class WorkerThread;
|
||||
|
||||
class ThreadPool
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
ThreadPool( const int threadNum );
|
||||
virtual ~ThreadPool();
|
||||
|
||||
void startWorkerThreads();
|
||||
|
||||
virtual void pushTask( Task* task );
|
||||
Task* popTask();
|
||||
|
||||
void stop();
|
||||
void join() const;
|
||||
|
||||
private:
|
||||
|
||||
ThreadPool( const ThreadPool& );
|
||||
ThreadPool& operator=( const ThreadPool& );
|
||||
|
||||
int m_threadNum;
|
||||
std::vector<WorkerThread*> m_threads;
|
||||
ConcurrentQueue<Task*> m_tasks;
|
||||
// Mutex m_mutex;
|
||||
};
|
||||
|
||||
|
||||
#endif // THREADPOOL_HPP */
|
@ -0,0 +1,26 @@
|
||||
#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
|
@ -0,0 +1,30 @@
|
||||
#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) );
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
#include "Thread.hpp"
|
||||
#include "Common.hpp"
|
||||
|
||||
#include <signal.h>
|
||||
#include <iostream>
|
||||
|
||||
Thread::Thread() : m_nThread( 0 )
|
||||
{
|
||||
TRACE(this);
|
||||
}
|
||||
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
TRACE(this);
|
||||
}
|
||||
|
||||
|
||||
void Thread::start()
|
||||
{
|
||||
TRACE(this);
|
||||
pthread_create( &m_nThread, NULL, threadStarter, ( void* )this );
|
||||
}
|
||||
|
||||
|
||||
void* Thread::join() const
|
||||
{
|
||||
TRACE(this);
|
||||
void* retVal;
|
||||
pthread_join( m_nThread, &retVal );
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
void Thread::sendSignal( const int nSignal ) const
|
||||
{
|
||||
TRACE(this);
|
||||
pthread_kill( m_nThread, nSignal );
|
||||
}
|
||||
|
||||
|
||||
void* Thread::threadStarter( void* pData )
|
||||
{
|
||||
TRACE("Thread::threadStarter");
|
||||
return static_cast<Thread *>(pData)->run();
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
#include "ThreadPool.hpp"
|
||||
#include "Common.hpp"
|
||||
|
||||
|
||||
ThreadPool::ThreadPool( const int threadNum ) : m_threadNum( threadNum )
|
||||
{
|
||||
TRACE(this);
|
||||
}
|
||||
|
||||
ThreadPool::~ThreadPool()
|
||||
{
|
||||
TRACE(this);
|
||||
std::vector<WorkerThread*>::iterator it;
|
||||
for( it = m_threads.begin() ; it != m_threads.end(); it++ )
|
||||
{
|
||||
delete (*it);
|
||||
}
|
||||
m_threads.clear();
|
||||
}
|
||||
|
||||
void ThreadPool::pushTask( Task* task )
|
||||
{
|
||||
TRACE(this);
|
||||
m_tasks.push(task);
|
||||
}
|
||||
|
||||
Task* ThreadPool::popTask()
|
||||
{
|
||||
TRACE(this);
|
||||
return m_tasks.waitAndPop();
|
||||
}
|
||||
|
||||
|
||||
void ThreadPool::startWorkerThreads()
|
||||
{
|
||||
TRACE(this);
|
||||
for( int i = 0; i<m_threadNum; i++ )
|
||||
{
|
||||
WorkerThread* t = new WorkerThread ( *this );
|
||||
m_threads.push_back( t );
|
||||
t->start();
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::stop()
|
||||
{
|
||||
TRACE(this);
|
||||
std::vector<WorkerThread*>::iterator it;
|
||||
for( it = m_threads.begin() ; it != m_threads.end(); it++ )
|
||||
{
|
||||
(*it)->stop();
|
||||
}
|
||||
|
||||
m_tasks.cancel();
|
||||
}
|
||||
|
||||
|
||||
void ThreadPool::join() const
|
||||
{
|
||||
TRACE(this);
|
||||
std::vector<WorkerThread*>::const_iterator it;
|
||||
for( it = m_threads.begin() ; it != m_threads.end(); it++ )
|
||||
{
|
||||
(*it)->join();
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (CPP_UTILS_TEST)
|
||||
|
||||
message(STATUS "Test dir:")
|
||||
|
||||
set (CXX_FLAGS "-Wall -Wextra -pedantic")
|
||||
add_definitions( ${CXX_FLAGS} )
|
||||
message(STATUS "g++ flags: ${CXX_FLAGS}")
|
||||
|
||||
include_directories (../include)
|
||||
message(STATUS "include dir: ${CPP_UTILS_LIB}/include")
|
||||
|
||||
add_executable (testThreadPool main_threadpool.cpp)
|
||||
target_link_libraries (testThreadPool CppUtils)
|
||||
|
||||
|
||||
find_package(CxxTest)
|
||||
if(CXXTEST_FOUND)
|
||||
set(CXXTEST_USE_PERL TRUE)
|
||||
include_directories(${CXXTEST_INCLUDE_DIR})
|
||||
enable_testing()
|
||||
# CXXTEST_ADD_TEST(unittest_sos check_sos.cpp ${SOS_TEST_PATH}/check_sos.h)
|
||||
# target_link_libraries(unittest_sos CppUtils)
|
||||
endif()
|
@ -0,0 +1,110 @@
|
||||
#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;
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
#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 const& 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;
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
#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;
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
#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;
|
||||
}
|
Loading…
Reference in new issue