i searched for an answer but couldnt find it. im working on threads. i have a thread class and 3 subclass of it. when i call one of these 3 subclass i have to create a thread in thread class and use their main(since threads main is pure virtual abstract) but the problem is before it call the Create Thread function(c'tor of thread) it calls those sub-mains.
thread.h
#ifndef _THREAD_H_
#define _THREAD_H_
#include <string>
#include <Windows.h>
#include <iosfwd>
#include "Mutex.h"
#include "SynchronizedArray.h"
#include "SynchronizedCounter.h"
std::string message = "";
class Thread{
private:
HANDLE hThread;
int idThread;
protected:
SynchronizedArray *arr;
int size;
SynchronizedCounter *counter;
public:
Thread(DWORD funct){ //creates a thread by calling subclasses main functions appropriately
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) funct, NULL, 0, (LPDWORD)&idThread);
}
virtual DWORD WINAPI main(void*) = 0; // pure virtual abstract class
void suspend(){ //suspent the thread
SuspendThread(hThread);
}
void resume(){// retume the thread
ResumeThread(hThread);
}
void terminate(){ // terminates the thread
TerminateThread(hThread,0);
}
void join(){ // joins the thread
Mutex mut;
mut.lock();
}
static void sleep(int sec){ //wrapper of sleep by sec
Sleep(sec*1000);
}
};
#endif
1 of 3 inherited class of Thread as example (all of them do the same)
PrintThread.h
#ifndef _PRINTINGTHREAD_H_
#define _PRINTINGTHREAD_H_
#include "SynchronizedArray.h"
#include "SynchronizedCounter.h"
#include "Thread.h"
#include <iostream>
#include "SortingThread.h"
#include "CountingThread.h"
#include <string>
#include <Windows.h>
extern CountingThread counterThread1;
extern CountingThread counterThread2;
extern SortingThread sortingThread1;
extern SortingThread sortingThread2;
class PrintingThread:public Thread{
private:
char temp;
public:
PrintingThread() :Thread(main(&temp)){
}
DWORD WINAPI main(void* param)
{
std::cout << "Please enter an operation ('showcounter1','showcounter2','showarray1','showarray2' or 'quit')" << std::endl;
std::cin >> message;
while (message != "quit")
{
if (message == "showcounter1")
{
std::cout << counterThread1<<std::endl;
}
else if (message == "showcounter2")
{
std::cout << counterThread2 << std::endl;
}
else if (message == "showarray1")
{
std::cout << sortingThread1 << std::endl;
}
else if (message == "showarray2")
{
std::cout << sortingThread2 << std::endl;
}
else {
std::cout << "Invalid operation";
}
std::cout << "Please enter an operation ('show counter 1','show counter 2','show array 1','show array 2' or 'quit')" << std::endl;
std::cin >> message;
}
return 0;
}
};
#endif
Why its calling mains before it calls the c'tor of thread.
Your PrintingThread constructor initializer list is actually calling PrintingThread::main and passing the result of that to the Thread constructor. That means that the CreateThread call is receiving a DWORD (in this case, 0) as its function argument.
You need to change your class design to actually pass the function pointer and context argument around, e.g.:
Thread(DWORD funct){
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) funct, NULL, 0, (LPDWORD)&idThread);
should be:
Thread(LPTHREAD_START_ROUTINE funct, LPVOID arg) {
hThread = CreateThread(NULL, 0, funct, arg, 0, (LPDWORD)&idThread);
(The fact that you had to cast funct should have been a giant red flag.)
Likewise, the subclass constructors will change from:
PrintingThread() :Thread(main(&temp)){
to:
PrintingThread(): Thread(main, &temp) {
Note that your code will still have other issues, like the fact that the thread functions should be static (so you can't try to access member functions).
you need to do something more like this instead:
thread.h:
#ifndef _THREAD_H_
#define _THREAD_H_
#include <string>
#include <Windows.h>
#include <iosfwd>
#include "Mutex.h"
#include "SynchronizedArray.h"
#include "SynchronizedCounter.h"
class Thread
{
private:
HANDLE hThread;
DWORD idThread;
void *pParam;
static DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
Thread *pThis = (Thread*) lpParameter;
return pThis->main(pThis->pParam);
}
protected:
SynchronizedArray *arr;
int size;
SynchronizedCounter *counter;
public:
Thread(void *aParam)
{
//creates a thread by calling subclasses main functions appropriately
pParam = aParam;
hThread = CreateThread(NULL, 0, &ThreadProc, this, 0, &idThread);
}
virtual DWORD main(void*) = 0; // pure virtual abstract class
void suspend()
{
//suspent the thread
SuspendThread(hThread);
}
void resume()
{
// resume the thread
ResumeThread(hThread);
}
void terminate()
{
// terminates the thread
TerminateThread(hThread, 0);
}
void join()
{
// joins the thread
Mutex mut;
mut.lock();
}
static void sleep(int sec)
{
//wrapper of sleep by sec
Sleep(sec*1000);
}
};
#endif
PrintThread.h:
include <iostream>
#include "SortingThread.h"
#include "CountingThread.h"
#include <string>
#include <Windows.h>
extern CountingThread counterThread1;
extern CountingThread counterThread2;
extern SortingThread sortingThread1;
extern SortingThread sortingThread2;
class PrintingThread : public Thread
{
private:
char temp;
public:
PrintingThread() : Thread(&temp)
{
}
virtual DWORD main(void* param)
{
std::string message;
do
{
std::cout << "Please enter an operation ('showcounter1','showcounter2','showarray1','showarray2' or 'quit')" << std::endl;
std::cin >> message;
if (message == "quit")
{
break;
}
if (message == "showcounter1")
{
std::cout << counterThread1 << std::endl;
}
else if (message == "showcounter2")
{
std::cout << counterThread2 << std::endl;
}
else if (message == "showarray1")
{
std::cout << sortingThread1 << std::endl;
}
else if (message == "showarray2")
{
std::cout << sortingThread2 << std::endl;
}
else
{
std::cout << "Invalid operation";
}
}
while (true);
return 0;
}
};
#endif
Related
I'm using std::thread to launch threads. Also, I need stats for the worker thread available at /proc/[pid]/tasks/[tid]. I need tid to be able to monitor thread stats. I was wondering if there was a way to extract tid from the parent thread. I know that syscall gettid() from the worker returns its id, but I want the threadId from the master and not the slave. Is there a way to extract tid from the thread_id gor from std::thread.get_tid() ?
I believe there might be better ways of doing this, please suggest :)
UPDATE:
How can you get the Linux thread Id of a std::thread() this provides some information on getting tid from the worker, adds an overhead to the thread launch. For instance, std::thread t = std::thread(&wrapper); t.get_id() can be called from the launcher thread. I was/am looking if there was a to do the same thing from the main/launcher thread in a safe way.
All threads have a unique id:
std::thread::id this_id = std::this_thread::get_id();
You can store it in a variable when the program starts and it'll be accessible from the other threads.
I understand what you mean when you say parent thread, but even though one thread gave birth to another, they are siblings.
if you want the master thread to be able to get the /proc path to each worker thread, you could wrap the worker thread object in a class that, when it starts the actual thread, creates a path property that the master can later get.
An example:
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
// A base class for thread object wrappers
class abstract_thread {
public:
abstract_thread() {}
abstract_thread(const abstract_thread&) = delete;
abstract_thread(abstract_thread&& rhs) :
m_th(std::move(rhs.m_th)), m_terminated(rhs.m_terminated), m_cv{}, m_mtx{} {}
abstract_thread& operator=(const abstract_thread&) = delete;
abstract_thread& operator=(abstract_thread&& rhs) {
terminate();
join();
m_th = std::move(rhs.m_th);
m_terminated = rhs.m_terminated;
return *this;
}
virtual ~abstract_thread() {
// make sure we don't destroy a running thread object
terminate();
join();
}
virtual void start() {
if(joinable())
throw std::runtime_error("thread already running");
else {
std::unique_lock<std::mutex> lock(m_mtx);
m_terminated = true;
// start thread and wait for it to signal that setup has been done
m_th = std::thread(&abstract_thread::proxy, this);
m_cv.wait(lock, [this] { return m_terminated == false; });
}
}
inline bool joinable() const { return m_th.joinable(); }
inline void join() {
if(joinable()) {
m_th.join();
}
}
inline void terminate() { m_terminated = true; }
inline bool terminated() const { return m_terminated; }
protected:
// override if thread specific setup needs to be done before start() returns
virtual void setup_in_thread() {}
// must be overridden in derived classes
virtual void execute() = 0;
private:
std::thread m_th{};
bool m_terminated{};
std::condition_variable m_cv{};
std::mutex m_mtx{};
void proxy() {
{
std::unique_lock<std::mutex> lock(m_mtx);
setup_in_thread(); // call setup function
m_terminated = false;
m_cv.notify_one();
}
execute(); // run thread code
}
};
// an abstract thread wrapper capable of returning its /proc path
class proc_path_thread : public abstract_thread {
public:
// function to call from master to get the path
const std::string& get_proc_path() const { return m_proc_path; }
protected:
void setup_in_thread() override {
m_proc_path =
std::move(std::string("/proc/")) + std::to_string(syscall(SYS_gettid));
}
private:
std::string m_proc_path{};
};
// two different thread wrapper classes. Just inherit proc_path_thread and implement
// "execute()". Loop until terminated() is true (or you're done with the work)
class AutoStartThread : public proc_path_thread {
public:
AutoStartThread() { start(); }
private:
void execute() override {
while(!terminated()) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << std::this_thread::get_id() << " AutoStartThread running\n";
}
}
};
class ManualStartThread : public proc_path_thread {
void execute() override {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << std::this_thread::get_id() << " ManualStartThread running\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
};
int main() {
AutoStartThread a;
std::cout << a.get_proc_path() << "\t// AutoStartThread, will have path\n";
ManualStartThread b;
std::cout << b.get_proc_path()
<< "\t// ManualStartThread not started, no path\n";
b.start();
std::cout << b.get_proc_path()
<< "\t// ManualStartThread will now have a path\n";
b.join();
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
// terminate() + join() is called automatically when abstract_thread descendants
// goes out of scope:
//
// a.terminate();
// a.join();
}
Possible output:
/proc/38207 // AutoStartThread, will have path
// ManualStartThread not started, no path
/proc/38208 // ManualStartThread will now have a path
139642064209664 ManualStartThread running
139642072602368 AutoStartThread running
139642072602368 AutoStartThread running
139642072602368 AutoStartThread running
139642072602368 AutoStartThread running
You can launch the thread through a function whose first task will be to message it's id, e.g., either classically using mutexes and condvars:
#include <stdio.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <unistd.h>
struct tid_msg{
pthread_mutex_t mx;
pthread_cond_t cond;
pid_t tid;
};
void *thr(void*A)
{
struct tid_msg *msg = A;
pid_t tid = syscall(SYS_gettid);
pthread_mutex_lock(&msg->mx);
msg->tid = tid;
pthread_mutex_unlock(&msg->mx);
pthread_cond_signal(&msg->cond);
printf("my tid=%lu\n", (long unsigned)tid);
return 0;
}
int main()
{
struct tid_msg msg = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, -1 };
pthread_t ptid;
pthread_create(&ptid,0,thr,&msg);
pthread_mutex_lock(&msg.mx);
while(-1==msg.tid) pthread_cond_wait(&msg.cond,&msg.mx);
pthread_mutex_unlock(&msg.mx);
printf("their tid=%lu\n", (long unsigned)msg.tid);
pthread_join(ptid,0);
}
or simply via an atomic variable (relaxed memory ordering should be fine here,
but you can play it safe and use the sequentially consistent default):
#include <stdio.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdatomic.h>
void *thr(void*A)
{
_Atomic pid_t *tidp = A;
pid_t tid;
tid = syscall(SYS_gettid);
atomic_store_explicit(tidp, tid, memory_order_relaxed);
printf("my tid=%lu\n", (long unsigned)tid);
return 0;
}
int main()
{
_Atomic pid_t tid=-1;
pthread_t ptid;
pthread_create(&ptid,0,thr,&tid);
while(-1==atomic_load_explicit(&tid,memory_order_relaxed)) ;
printf("their tid=%lu\n", (long unsigned)tid);
pthread_join(ptid,0);
}
I have written a simple singleton application.
The following is my sample main class
// ThreadsafeSingletonUsingSemaphore.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <conio.h>
#include "MySingleton.h"
using namespace std;
int i =0;
#define THREADCOUNT 100
DWORD WINAPI ThreadProc(LPVOID lParam);
HANDLE g_semaphore = NULL;
int _tmain(int argc, _TCHAR* argv[])
{
g_semaphore = CreateSemaphore(NULL,1,1,_T("TreadOne"));
HANDLE hThread[THREADCOUNT];
DWORD aThreadID;
for(int iCount = 0; iCount < THREADCOUNT ; iCount++)
{
hThread[iCount] = CreateThread(NULL, 0, ThreadProc, 0,0, &aThreadID);
if( hThread[iCount] == NULL )
{
cout<<"CreateThread error: %d" << GetLastError() << endl;
return 1;
}
}
WaitForMultipleObjects(THREADCOUNT, hThread, TRUE, INFINITE);
// Close thread and semaphore handles
for(int i=0; i < THREADCOUNT; i++ )
CloseHandle(hThread[i]);
cout << MySingleton::getInstance().getCounter() << endl ;
CloseHandle(g_semaphore);
_getch();
return 0;
}
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
//DWORD result = WaitForSingleObject(g_semaphore,INFINITE);
//if(WAIT_OBJECT_0 == result)
MySingleton::getInstance().incrementCouner();
//ReleaseSemaphore(g_semaphore,1, NULL);
return TRUE;
}
This is my singleton implementation class.
#include "StdAfx.h"
#include "MySingleton.h"
MySingleton* MySingleton::m_instance = NULL;
HANDLE MySingleton::m_hSem = CreateSemaphore(NULL, 1, 1, _T("MySingleton"));
HANDLE MySingleton::m_One = CreateSemaphore(NULL, 1, 1, _T("MyOne"));
MySingleton::MySingleton(void) : m_counter(0)
{
}
MySingleton::~MySingleton(void)
{
cout << "destructor" << endl;
CloseHandle(m_hSem);
CloseHandle(m_One);
}
MySingleton& MySingleton::getInstance()
{
DWORD result = WaitForSingleObject(m_hSem, INFINITE);
if(WAIT_OBJECT_0 == result)
{
if(m_instance == NULL)
{
cout << "creating" << endl;
m_instance = new MySingleton();
}
}
ReleaseSemaphore(m_hSem,1,NULL);
return *m_instance;
}
void MySingleton::setCouner(int iCount_in)
{
m_counter = iCount_in;
}
int MySingleton::getCounter()
{
return m_counter;
}
void MySingleton::incrementCouner()
{
DWORD result = WaitForSingleObject(m_One, INFINITE);
if(WAIT_OBJECT_0 == result)
m_counter++;
ReleaseSemaphore(m_One,1,NULL);
}
This is my .h class.
#pragma once
#include <windows.h>
#include <iostream>
#include <conio.h>
using namespace std;
class MySingleton
{
private:
static HANDLE m_hSem, m_One;
HANDLE m_hCountSem;
static MySingleton* m_instance;
int m_counter;
MySingleton();
MySingleton(const MySingleton& obj_in);
MySingleton& operator=(const MySingleton& obj_in);
public:
~MySingleton(void);
static MySingleton& getInstance();
void setCouner(int iCount_in);
int getCounter();
void incrementCouner();
};
The problem is the final value of counter is never 100. can someone please explain me why and what is that i am doing wrong.I am not able to understand the problem. When I introduce sleep in the main before creating each thread, it works fine.
The problem is that call to WaitForMultipleObjects handles up to MAXIMUM_WAIT_OBJECTS which, at least in Visual Studio 2017, is 64.
Notice how your call to WaitForMultipleObjects to join threads returns WAIT_FAILED.
In order to wait for more objects one should, according to the documentation:
To wait on more than MAXIMUM_WAIT_OBJECTS handles, use one of the following methods:
Create a thread to wait on MAXIMUM_WAIT_OBJECTS handles, then wait on that thread plus the other handles. Use this technique to break the handles into groups of MAXIMUM_WAIT_OBJECTS.
Call RegisterWaitForSingleObject to wait on each handle. A wait thread from the thread pool waits on MAXIMUM_WAIT_OBJECTS registered objects and assigns a worker thread after the object is signaled or the time-out interval expires.
You don't need to write all of that code. The easiest way to implement a threadsafe singleton is to use Scott Meyer's singleton idiom:
class Singleton {
int counter;
mutable std::mutex counter_guard;
Singleton() {}
public:
Singleton(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton& operator=(Singleton&&) = delete;
static Singleton& instance() {
static Singleton theInstance;
return theInstance;
}
void setCounter(int newVal) {
std::unique_lock<std::mutex> lock(counter_guard);
counter = newVal;
}
void incrementCounter() {
std::unique_lock<std::mutex> lock(counter_guard);
++counter;
}
int getCounter() const {
std::unique_lock<std::mutex> lock(counter_guard);
return counter;
}
};
An even easier way would be to use a std::atomic<int> type for the counter member variable. Then the mutex and lock guards can be omitted at all.
Below is my code, my problem is that readEvent() function never gets called.
Header file
class MyServer
{
public :
MyServer(MFCPacketWriter *writer_);
~MyServer();
void startReading();
void stopReading();
private :
MFCPacketWriter *writer;
pthread_t serverThread;
bool stopThread;
static void *readEvent(void *);
};
CPP file
MyServer::MyServer(MFCPacketWriter *writer_):writer(writer_)
{
serverThread = NULL;
stopThread = false;
LOGD(">>>>>>>>>>>>> constructed MyServer ");
}
MyServer::~MyServer()
{
writer = NULL;
stopThread = true;
}
void MyServer::startReading()
{
LOGD(">>>>>>>>>>>>> start reading");
if(pthread_create(&serverThread,NULL,&MyServer::readEvent, this) < 0)
{
LOGI(">>>>>>>>>>>>> Error while creating thread");
}
}
void *MyServer::readEvent(void *voidptr)
{
// this log never gets called
LOGD(">>>>>>>>>>>>> readEvent");
while(!MyServer->stopThread){
//loop logic
}
}
Another class
MyServer MyServer(packet_writer);
MyServer.startReading();
Since you are not calling pthread_join, your main thread is terminating without waiting for your worker thread to finish.
Here is a simplified example that reproduces the problem:
#include <iostream>
#include <pthread.h>
class Example {
public:
Example () : thread_() {
int rcode = pthread_create(&thread_, nullptr, Example::task, nullptr);
if (rcode != 0) {
std::cout << "pthread_create failed. Return code: " << rcode << std::endl;
}
}
static void * task (void *) {
std::cout << "Running task." << std::endl;
return nullptr;
}
private:
pthread_t thread_;
};
int main () {
Example example;
}
View Results
No output is produced when running this program, even though pthread_create was successfully called with Example::task as the function parameter.
This can be fixed by calling pthread_join on the thread:
#include <iostream>
#include <pthread.h>
class Example {
public:
Example () : thread_() {
int rcode = pthread_create(&thread_, nullptr, Example::task, nullptr);
if (rcode != 0) {
std::cout << "pthread_create failed. Return code: " << rcode << std::endl;
}
}
/* New code below this point. */
~Example () {
int rcode = pthread_join(thread_, nullptr);
if (rcode != 0) {
std::cout << "pthread_join failed. Return code: " << rcode << std::endl;
}
}
/* New code above this point. */
static void * task (void *) {
std::cout << "Running task." << std::endl;
return nullptr;
}
private:
pthread_t thread_;
};
int main () {
Example example;
}
View Results
Now the program produces the expected output:
Running task.
In your case, you could add a call to pthread_join to the destructor of your MyServer class.
I am trying to develop a console application, where I will display the system date and time in real time (or as real as I can get). This is the easy part. The hard part is that I must also have the cursor available for the user to enter information through. I can't use NCurses in my application, nor any other library that it not included in vanilla GCC 4.4 (there goes boost! Noooo....)
This is my code so far:
The realtime class, where I am incorporating the solution given by Jeremy Friesner here pthreads in c++ inside classes
#ifndef _REALTIME_H_
#define _REALTIME_H_
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
class MyThreadClass
{
public:
MyThreadClass() {/* empty */}
virtual ~MyThreadClass() {/* empty */}
/** Returns true if the thread was successfully started, false if there was an error starting the thread */
bool startMainThread()
{
return (pthread_create(&_mainThread, NULL, mainRunnerFunc, this) == 0);
}
bool startDisplayThread()
{
return (pthread_create(&_displayThread, NULL, displayThreadFunc, this) == 0);
}
/** Will not return until the main thread has exited. */
void waitForMainThreadToExit()
{
(void) pthread_join(_mainThread, NULL);
}
void waitForDisplayThreadToExit()
{
(void) pthread_join(_displayThread, NULL);
}
protected:
/** Implement this method in your subclass with the code you want your thread to run. */
virtual void mainRunner() = 0;
virtual void displayTime() = 0;
private:
static void * mainRunnerFunc(void * This) {((MyThreadClass *)This)->mainRunner(); return NULL;}
static void * displayThreadFunc(void * This) {((MyThreadClass *)This)->displayTime(); return NULL;}
pthread_t _mainThread;
pthread_t _displayThread;
};
class DynamicTime : public MyThreadClass
{
private:
const string currentDate();
void gotoxy(int,int);
void displayTime();
void mainRunner();
pthread_mutex_t mutex1;
public:
// pthread_mutex_t mutex1;
DynamicTime();
unsigned int lifeTime;
unsigned int updateTime;
void start();
int Exit;
};
const string DynamicTime::currentDate()
{
time_t now = time(0);
struct tm tstruct;
char buf[80];
tstruct = *localtime(&now);
strftime(buf,sizeof(buf),"%I:%M:%S %p, %d-%m-%y",&tstruct);
return buf;
}
DynamicTime::DynamicTime()
{
pthread_mutex_init(&(mutex1),NULL);
lifeTime=-1; /* 100 seconds */
updateTime = 1; /* 5 seconds interval */
Exit=1;
}
void DynamicTime::gotoxy(int x,int y)
{
/* go to location */
printf("\033[%d;%df",y,x);
}
void DynamicTime::displayTime()
{
pthread_mutex_lock(&mutex1);
/* save the cursor location */
printf("\033[s");
gotoxy(75,30);
cout << "Date : " << currentDate() << endl;
/* restore the cursor location */
printf("\033[u");
pthread_mutex_unlock(&mutex1);
}
void DynamicTime::mainRunner()
{
unsigned long iterate, iterate2;
int iret1,iret2;
if(lifeTime!=-1)
{
for(iterate=0;iterate<lifeTime*100000;iterate++)
{
if(iterate%(updateTime*50)==0)
{
iret2 = startDisplayThread();
waitForDisplayThreadToExit();
}
for(iterate2=0;iterate2<100000;iterate2++);
}
std::cout << "Ending main thread..." << endl;
}
else
{
while(1&Exit) /* infinitely */
{
iret2 = startDisplayThread();
waitForDisplayThreadToExit();
for(iterate2=0;iterate2<100000;iterate2++);
}
std::cout << "Exiting Application.... " << endl;
}
}
void DynamicTime::start()
{
//system("clear");
//cout << "Starting...." << endl;
if(startMainThread()==false)
{
std::cerr << "Coudln't start main Thread! " << endl;
}
/* call this function in the main program
* else
{
waitForMainThreadToExit();
}*/
}
/* Example
* on how to use the program
* int main()
{
DynamicTime DT;
DT.lifeTime = 100;
DT.start();
return 0;
}
*/
#endif
and my example program, where I am trying to read data from the user, while showing the time at the same time:
//#include <iostream>
#include "realtime2.h"
int main()
{
DynamicTime DT;
string temp="abcd";
DT.start();
while(temp!="exit")
{
std::cout << "$> " ;
std::cin >> temp;
}
DT.waitForMainThreadToExit();
return 0;
}
This would be called a fully-functional program, if only I could get the user to enter data without interruption from the display thread. Any ideas as to how to get around this ? Or if I can't get around this, what would be the proper way to do so ?
Running on:
mehoggan#mehoggan-laptop:~/Code/svn_playground/C++/timer/timer0$ uname -a
Linux mehoggan-laptop 2.6.32-37-generic #81-Ubuntu SMP Fri Dec 2 20:32:42 UTC 2011 x86_64 GNU/Linux
mehoggan#mehoggan-laptop:~/Code/svn_playground/C++/timer/timer0$ cat /etc/*release*
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=10.04
DISTRIB_CODENAME=lucid
DISTRIB_DESCRIPTION="Ubuntu 10.04.3 LTS"
mehoggan#mehoggan-laptop:~/Code/svn_playground/C++/timer/timer0$ g++ --version
g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
mehoggan#mehoggan-laptop:~/Code/svn_playground/C++/timer/timer0$
I am trying to write a timer class that runs on a background thread and uses gettimeofday(3) function plus a user specified callback function. The usage of this will be in a OpenGL app I am in the process of porting from Windows to Linux.
When I run this code (see below). My threads get hung up when running in release mode. However, when I step through the code with a debugger everything seems to work just fine. This indicates a timing issue to me. I might be wrong about this since I am just now learning how to use threads. Could someone help me understand why my threaded application is getting this signal from the OS?
There are two place you can get the code, you can download it from my trac site:
Trac Site
Or you can just copy and paste:
MAIN.CPP
#include "TimerManager.h"
#include <iostream>
#include <fstream>
#include <sys/time.h>
std::ofstream out;
void func1(int id)
{
struct timeval l_tv;
gettimeofday(&l_tv, NULL);
std::cout << "I was called (1) # " << l_tv.tv_usec << std::endl;
out.flush();
}
void func2(int id)
{
struct timeval l_tv;
gettimeofday(&l_tv, NULL);
std::cout << "I was called (2) # " << l_tv.tv_usec << std::endl;
out.flush();
}
int main(int, char *[])
{
out.open("/home/mehoggan/Desktop/log.log");
TimerManager t;
t.addTimer(1000000 * 10, func1);
t.addTimer(1000000 * 20, func2);
t.start();
while(true) {
sleep(1);
}
return 0;
}
#ifndef TIMERMANAGER_H_
#define TIMERMANAGER_H_
#include <stdlib.h>
#include <iostream>
#include <pthread.h>
#include <list>
extern "C" {
void *create_pthread(void *data);
}
class TimerManager {
public:
TimerManager();
~TimerManager();
void start();
void stop();
void addTimer(long usec, void (*callback)(int id));
private:
class Timer
{
public:
Timer(long usec, void (*callback)(int)) :
duration(usec),
callback(callback),
start(0)
{
}
bool operator ==(Timer other)
{
if ((this->callback == other.callback) && (this->duration == other.duration)) {
return true;
}
return false;
}
void operator =(Timer other)
{
duration = other.duration;
callback = other.callback;
start = other.start;
}
suseconds_t duration;
void (*callback)(int);
suseconds_t start;
};
std::list<Timer> m_timers;
Timer setUpTimer(long micro_duration, void (*callback)(int id));
friend void *create_pthread(void *data);
void run();
bool m_bRunning;
bool m_bGo;
long m_lMinSleep;
pthread_t m_tTimerThread;
pthread_cond_t m_tGoLockCondition;
pthread_mutex_t m_tGoLock;
};
#endif
#include <algorithm>
#include <iterator>
#include <sys/time.h>
#include "TimerManager.h"
extern "C" void *create_pthread(void *data)
{
TimerManager *thread_timer_manager = static_cast<TimerManager *>(data);
thread_timer_manager->run();
return data;
}
TimerManager::TimerManager() :
m_bRunning(false),
m_bGo(false),
m_lMinSleep(0)
{
int mutex_creation = pthread_mutex_init(&m_tGoLock, NULL);
if(mutex_creation != 0) {
std::cerr << "Failed to create mutex" << std::endl;
return;
}
int mutex_cond_creation = pthread_cond_init(&m_tGoLockCondition, NULL);
if(mutex_cond_creation != 0) {
std::cerr << "Failed to create condition mutex" << std::endl;
return;
}
int thread_creation = pthread_create(&m_tTimerThread, NULL, create_pthread, this);
if(thread_creation != 0) {
std::cerr << "Failed to create thread" << std::endl;
return;
}
m_bRunning = true;
}
TimerManager::~TimerManager()
{
m_bRunning = false;
pthread_mutex_destroy(&m_tGoLock);
void *result;
pthread_join(m_tTimerThread, &result);
}
void TimerManager::run()
{
pthread_mutex_lock(&m_tGoLock);
while(m_bRunning) {
while (!m_bGo) {
pthread_cond_wait(&m_tGoLockCondition, &m_tGoLock);
}
pthread_mutex_unlock(&m_tGoLock);
if (!m_bRunning) {
break;
}
pthread_detach(m_tTimerThread);
struct timeval l_tv;
sleep(std::max(0l, m_lMinSleep));
gettimeofday(&l_tv, NULL);
m_lMinSleep = 0;
long l_lMin = 0;
for(std::list<Timer>::iterator it = m_timers.begin(); it != m_timers.end(); ++it) {
TimerManager::Timer l_oTimer = *it;
long elapsed_time = ((l_tv.tv_sec * 1000000 + l_tv.tv_usec) - (l_oTimer.start));
l_lMin = elapsed_time - l_oTimer.duration;
if (elapsed_time >= l_oTimer.duration) {
l_lMin = l_oTimer.duration;
l_oTimer.callback(0);
gettimeofday(&l_tv, NULL);
it->start = (l_tv.tv_sec * 1000000) + l_tv.tv_usec;
}
m_lMinSleep = std::min(m_lMinSleep, l_lMin);
}
}
}
void TimerManager::start()
{
pthread_mutex_lock(&m_tGoLock);
m_bGo = true;
pthread_cond_signal(&m_tGoLockCondition);
pthread_mutex_unlock(&m_tGoLock);
}
void TimerManager::stop()
{
pthread_mutex_lock(&m_tGoLock);
m_bGo = false;
pthread_mutex_unlock(&m_tGoLock);
}
TimerManager::Timer TimerManager::setUpTimer(long micro_duration, void (*callback)(int id))
{
struct timeval l_tv;
gettimeofday(&l_tv, NULL);
Timer l_oTimer(micro_duration, callback);
l_oTimer.start = (l_tv.tv_sec * 1000000) + l_tv.tv_usec;
return l_oTimer;
}
void TimerManager::addTimer(long usec, void (*callback)(int id))
{
Timer insert = setUpTimer(usec, callback);
typedef std::list<Timer>::iterator li;
m_timers.push_back(insert);
}
Well, your destructor is definitely broken. You can't destroy a mutex while another thread might be using it. And you can't modify m_bRunning while another thread might be accessing it. You want:
TimerManager::~TimerManager()
{
pthread_mutex_lock(&m_tGoLock);
m_bRunning = false;
pthread_mutex_unlock(&m_tGoLock);
void *result;
pthread_join(m_tTimerThread, &result);
pthread_mutex_destroy(&m_tGoLock);
}
You have a lot of concurrency bugs. For example, your addTimer function modifies the shared m_timers structure without holding a mutex.