sem_timedwait with CLOCK_MONOTONIC_RAW/CLOCK_MONOTONIC - c++

The example code for int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); uses CLOCK_REALTIME as the time source from clock_gettime(struct timespec *timeout) but this is susceptible to system clock time changes for example some other process changing time backwards.
Is there a support for sem_timedwait to support CLOCK_MONOTONIC time source
below is some example code for reference.
struct timespec ts;
sem_t sema;
sem_init(&sema, 0, 0)
int ret;
if ( -1 != (ret = clock_gettime(CLOCK_REALTIME, &ts))){
ts.tv_sec += 1;
return sem_timedwait(sema, &ts);
}

Is there a support for sem_timedwait to support CLOCK_MONOTONIC time source
Short answer: no.
But you could implement one if you're not using a 3rd party library or C++11 and don't need cross-platform compatibility:
#include <cstring> // memset
#include <ctime> // DEV_NOTE: some systems might need -lrt
#include <csignal> // DEV_NOTE: csignal contains a reference to CLOCK_MONOTONIC
#include <semaphore.h>
#if !defined(CLOCK_MONOTONIC)
#error CLOCK_MONOTONIC is not defined
#endif
typedef struct timespec tick_t;
static tick_t monotonic_tick()
{
tick_t tmp;
if (clock_gettime(CLOCK_MONOTONIC, &tmp) != 0) {
std::memset(&tmp, 0, sizeof(tick_t));
// error, throw std::exception(std::strerror(errno))
}
return tmp;
}
static double elapsed_us(tick_t init, tick_t end)
{
return ((end.tv_sec - init.tv_sec) * 1000000) + (static_cast<double>((end.tv_nsec - init.tv_nsec)) / 1000);
}
static double elapsed_ms(tick_t init)
{
return (elapsed_us(init, monotonic_tick()) / 1000);
}
static int sem_timed_wait(sem_t& sem, unsigned long timeout_ms)
{
if (timeout_ms == 0) {
if (sem_trywait(&sem) == 0) {
return 0;
}
} else {
tick_t start = monotonic_tick();
do {
if (sem_trywait(&sem) == 0) {
return 0;
}
} while (elapsed_ms(start) <= timeout_ms);
}
return -1;
}
Then to use it:
#include <iostream>
#include <pthread.h>
void* thread_fn(void* val)
{
sem_t* sem = static_cast<sem_t*>(val);
std::cout << std::endl << pthread_self() << " thread started" << std::endl;
if (sem_timed_wait(*sem, 1000) == 0) {
std::cout << std::endl << pthread_self() << " got it, sleeping 2 seconds..." << std::endl;
sleep(2); // sleep 2 seconds
std::cout << pthread_self() << " returning..." << std::endl;
// don't forget to release since we acquired the lock
sem_post(sem);
} else {
std::cout << pthread_self() << " timeout" << std::endl;
}
std::cout << pthread_self() << " thread returning" << std::endl;
return NULL;
}
int main(int argc, char* argv[])
{
sem_t sem;
pthread_t t1, t2;
sem_init(&sem, 0, 1); // binary semaphore
std::cout << "Creating..." << std::endl;
pthread_create(&t1, NULL, thread_fn, static_cast<void*>(&sem));
pthread_create(&t2, NULL, thread_fn, static_cast<void*>(&sem));
std::cout << "Joining..." << std::endl;
pthread_join(t1, NULL);
pthread_join(t2, NULL);
std::cout << "Leaving..." << std::endl;
return 0;
}
The above works on a wide array of *nix systems to include the BSD line. If you need a cross platform way of doing this, Windows and Apple have simpler mechanisms to do this.
Hope that can help.

Had the same problem with POSIX system,
Based on C++0x has no semaphores? How to synchronize threads?
and How do I deal with the system clock changing while waiting on a std::condition_variable? and Halûk Uçar answer
#include <stdio.h>
#include <thread>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
class semaphore
{
private:
pthread_mutex_t m_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_condattr_t m_attr;
pthread_cond_t m_cond;
unsigned long count_ = 0;
public :
void init_sem()
{
int result = 0;
result = pthread_condattr_init(&m_attr);
result = pthread_condattr_setclock(&m_attr, CLOCK_MONOTONIC);
result = pthread_cond_init(&m_cond, &m_attr);
}
void notify() {
pthread_mutex_lock(&m_mutex);
++count_;
pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex);
}
void wait() {
pthread_mutex_lock(&m_mutex);
while (!count_) // Handle spurious wake-ups.
{
pthread_cond_wait(&m_cond, &m_mutex);
}
--count_;
pthread_mutex_unlock(&m_mutex);
}
void wait_for(int sec)
{
int rc = 0;
pthread_mutex_lock(&m_mutex);
if (!count_)
{
timespec tsTimeout;
clock_gettime(CLOCK_MONOTONIC, &tsTimeout);
// update time calculation to your specific case
tsTimeout.tv_sec += time;
// Handle spurious wake-ups.
while (!count_ && (rc == 0))
{
rc = pthread_cond_timedwait(&m_cond, &m_mutex, &tsTimeout);
}
}
if (rc == 0)
{
printf("success\n");
--count_;
}
else if (rc == ETIMEDOUT)
{
printf("timeout\n");
}
else
{
printf("error\n");
}
pthread_mutex_unlock(&m_mutex);
}
bool destroy()
{
return ((pthread_cond_destroy(&m_cond) == 0)
&& (pthread_mutex_destroy(&m_mutex) == 0)
&& (pthread_condattr_destroy(&m_attr)==0)) ? true : false;
}
};

You can implement your own semaphore routines by using
pthread_cond_signal() for sem_post()
pthread_cond_timedwait() for sem_timedwait()
pthread_cond_wait() for sem_wait()
pthread_cond_timedwait() at current time for sem_trywait()
Of course semaphore creation and deletion will include malloc and free, where you alloc a struct with all parameters (mutex, condition, ... ) needed for your semaphore implementation.

If anyone stumbles across this in the future:
glibc has now implemented this (since version 2.30):
https://www.gnu.org/software/libc/manual/html_node/Waiting-with-Explicit-Clocks.html
you can use sem_clockwait with CLOCK_MONOTONIC.

Related

A two-thread problem that the program never exit as I expect

I designed a simple logging component, but I encountered some problems. The Logging object will create a thread to save logs from buffer in the background. The main thread writes logs into buffer. However, because I use pthread_detach, the main thread will exit even if the Logging thread is still working.
I use pthread_cond_t to solve that problem. I set the LastWriteTime, which represents the last time when main thread wrote to the log. If there has been no log for a period of time, the Logging thread will notify the main thread.
But the program blocks and never exits.
#include <string>
#include <cstring>
#include <string.h>
#include <iostream>
#include <pthread.h>
#include <sys/time.h>
using namespace std;
int64_t get_current_millis(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
void *run(void *args);
class Logging
{
public:
static Logging *LoggingPtr;
pthread_mutex_t ExitMutex;
pthread_cond_t ExitCond;
struct timeval LastWriteTime;
Logging() : ExitMutex(PTHREAD_MUTEX_INITIALIZER), ExitCond(PTHREAD_COND_INITIALIZER)
{
pthread_t pid;
pthread_create(&pid, NULL, run, NULL);
pthread_detach(pid);
}
bool CheckExpired(struct timeval lastWriteTime, size_t wait_time)
{
struct timeval now;
gettimeofday(&now, NULL);
long now_sec = now.tv_sec * 1000 + now.tv_usec / 1000;
long last_sec = lastWriteTime.tv_sec * 1000 + lastWriteTime.tv_usec / 1000;
// expired time: wait_time(ms)
return now_sec - last_sec > wait_time ? true : false;
}
void Save()
{
cout << "in the save" << endl;
while (true)
{
if (CheckExpired(LastWriteTime, 3000))
{
pthread_cond_signal(&ExitCond);
}
}
}
static Logging *Init()
{
while (!LoggingPtr)
{
LoggingPtr = new Logging();
}
return LoggingPtr;
}
void Append()
{
for (size_t i = 0; i < 100000; i++)
{
pthread_mutex_lock(&ExitMutex);
gettimeofday(&LastWriteTime, NULL);
pthread_mutex_unlock(&ExitMutex);
}
}
void Exit()
{
while (true)
{
if (CheckExpired(LastWriteTime, 3000))
{
pthread_cond_signal(&ExitCond);
}
}
pthread_mutex_lock(&ExitMutex);
// 3000 means that the wait_time is 3s
while (!CheckExpired(this->LastWriteTime, 3000))
{
pthread_cond_wait(&ExitCond, &ExitMutex);
}
pthread_mutex_unlock(&ExitMutex);
}
};
void *run(void *args)
{
Logging::Init()->Save();
return NULL;
}
Logging *Logging::LoggingPtr = nullptr;
int main()
{
uint64_t start_ts = get_current_millis();
Logging LOG;
LOG.Append();
LOG.Exit();
uint64_t end_ts = get_current_millis();
std::cout << "wait " << (end_ts - start_ts) / 1000 << "s" << std::endl;
return 0;
}

boost interprocess message_queue and fork

I am trying to communicate with forked child process using message queue from boost interprocess library. When child process calls receive it causes exception with message
boost::interprocess_exception::library_error
I am using GCC 6.3 on Debian 9 x64.
#include <iostream>
#include <unistd.h>
#include <boost/interprocess/ipc/message_queue.hpp>
#include <memory>
int main(int argc, char* argv[])
{
using namespace boost::interprocess;
const char* name = "foo-552b8ae9-6037-4b77-aa0d-d4dc9dad790b";
const int max_num_msg = 100;
const int max_msg_size = 32;
bool is_child = false;
message_queue::remove(name);
auto mq = std::make_unique<message_queue>(create_only, name, max_num_msg, max_msg_size);
auto child_pid = fork();
if (child_pid == -1)
{
std::cout << "fork failed" << std::endl;
return -1;
}
else if (child_pid == 0)
{
is_child = true;
}
if (is_child)
{
// does child needs to reopen it?
mq.reset( new message_queue(open_only, name) );
}
int send_num = 0;
while(true)
{
unsigned int priority = 0;
if (is_child)
{
message_queue::size_type bytes = 0;
try
{
int num;
// Always throws. What is wrong ???????
mq->receive(&num, sizeof(num), bytes, priority);
std::cout << num << std::endl;
}
catch(const std::exception& e)
{
std::cout << "Receive caused execption " << e.what() << std::endl;
}
sleep(1);
}
else
{
mq->send(&send_num, sizeof(send_num), priority);
send_num++;
sleep(5);
}
}
return 0;
}
Also, in child process is it required to reopen the message queue created by the parent process? I tried it both ways and neither worked. I am getting the same exception on receive.
The problem is that your receive buffer is smaller than max_msg_size. Assuming 4-byte integers, this should work:
int num[8];
mq.receive(num, sizeof(num), bytes, priority);
std::cout << *num << std::endl;
Also, I see no reason to play fast and loose with the actual queue instance. Just create it per process:
#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <iostream>
#include <memory>
#include <unistd.h>
int main() {
namespace bip = boost::interprocess;
const char *name = "foo-552b8ae9-6037-4b77-aa0d-d4dc9dad790b";
{
const int max_num_msg = 100;
const int max_msg_size = 32;
bip::message_queue::remove(name);
bip::message_queue mq(bip::create_only, name, max_num_msg, max_msg_size);
}
auto child_pid = fork();
if (child_pid == -1) {
std::cout << "fork failed" << std::endl;
return -1;
}
bip::message_queue mq(bip::open_only, name);
if (bool const is_child = (child_pid == 0)) {
while (true) {
unsigned int priority = 0;
bip::message_queue::size_type bytes = 0;
try {
int num[8];
mq.receive(num, sizeof(num), bytes, priority);
std::cout << *num << std::endl;
} catch (const bip::interprocess_exception &e) {
std::cout << "Receive caused execption " << boost::diagnostic_information(e, true) << std::endl;
}
sleep(1);
}
} else {
// parent
int send_num = 0;
while (true) {
unsigned int priority = 0;
mq.send(&send_num, sizeof(send_num), priority);
send_num++;
sleep(5);
}
}
}

c++ threading: cv.notify_one() blocks?

I wrote the following structure to implement a simple single producer / multi consumer synchronization. I'm using two integers available_index and consumed_index, access to consumed_index is protected by the condition variable cv. Here's the code:
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <thread>
struct ParserSync {
std::mutex worker_lock;
std::condition_variable cv;
int consumed_index = -1;
int available_index = -1;
bool exit_flag = false;
int consume_index() {
int ret = -1;
// get worker_lock
std::unique_lock<std::mutex> w_lock(worker_lock);
// wait for exit_flag or new available index
cv.wait(w_lock, [this] { return exit_flag || available_index > consumed_index; });
if (available_index > consumed_index) {
consumed_index++;
ret = consumed_index;
}
// Unlock mutex and notify another thread
w_lock.unlock();
cv.notify_one();
return ret;
}
void publish_index() {
available_index++;
std::cout << "before" << std::endl;
cv.notify_one();
std::cout << "after" << std::endl;
}
void set_exit() {
exit_flag = true;
cv.notify_all();
}
};
I tested my implementation using the following code (just a simple example to show the problem):
void producer(ParserSync &ps){
for (int i=0;i<5000;i++){
ps.publish_index();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
ps.set_exit();
std::cout << "Producer finished!" << std::endl;
}
void consumer(ParserSync &ps){
while (true){
int idx = ps.consume_index();
if (idx == -1)
break;
std::this_thread::sleep_for(std::chrono::milliseconds(4));
}
std::cout << "Consumer finished!" << std::endl;
}
int main() {
ParserSync ps{};
const int num_consumers = 4;
std::vector<std::thread> consumer_threads(num_consumers);
// start consumers
for (int i = 0; i < num_consumers; ++i) {
consumer_threads[i] = std::thread{consumer, std::ref(ps)};
}
// start producer
std::thread producer_thread = std::thread{producer, std::ref(ps)};
for (int i = 0; i < num_consumers; ++i) {
consumer_threads[i].join();
}
producer_thread.join();
std::cout << "Program finished" << std::endl;
return 0;
}
I would expect that producer thread produces 5000 indices and exits afterwards, but unfortunately, it gets stuck at some random iteration. I used print statements to find the code line that blocks and tracked it down to cv.notify_one();. This is the (shortened) console output:
...
before
after
before
after
before
Does anyone know why the call to cv.notify_one(); blocks?
I'm using MinGW (x86_64-6.2.0-posix-seh-rt_v5-rev1) on Windows 10.
Thanks in advance!
EDIT:
When compiling the exact same code with Visual Studio, the program works as expected and doesn't lock itself up. Unfortunately, I need to use MinGW for other reasons.

the magic cout that keep my program alive

I wrote a code to implement spin lock and mutex lock.
There is an interesting but. A magic cout can keep my program alive. If I remove the cout, my program will be sleeping forever. (This only happens in Linux. Windows is doing fine)
Any one have a clue?
#include <pthread.h>
#include <iostream>
#include <queue>
#include <sys/time.h>
#include <stdexcept>
#include <cstdio>
#include <cstdlib>
using namespace std;
#define Tcount 10
#define TheLock MutexLock
static inline int TAS(volatile int * ptr) {
unsigned long result;
asm volatile("lock;"
"xchgl %0, %1;"
: "=r"(result), "=m"(*ptr)
: "0"(1), "m"(*ptr)
: "memory");
return result;
}
class SpinLock {
private:
int lock;
pthread_t owner;
public:
SpinLock() {
lock = 0;
}
void getLock() {
while (TAS(&lock) == 1) {
}
owner = pthread_self();
}
void releaseLock() {
if (lock == 0) {
cout << "Spin no lock" << endl;
return;
} else if (owner == pthread_self()) {
owner = NULL;
lock = 0;
} else {
throw runtime_error("Spin can't release");
}
}
};
class MutexLock {
private:
int lock;
pthread_t owner;
queue<pthread_t> q;
SpinLock qLock;
public:
MutexLock() {
lock = 0;
}
void getLock(int id) {
pthread_t self = pthread_self();
cout<<"a"<<endl;// magic cout
if (TAS(&lock) == 0) {
owner = self;
return;
}
qLock.getLock();
q.push(self);
qLock.releaseLock();
while (owner != self) {
}
}
void releaseLock(int id) {
if (lock == 0) {
cout << "Mutex no lock" << endl;
return;
} else if (owner == pthread_self()) {
qLock.getLock();
if (q.empty()) {
owner = NULL;
lock = 0;
} else {
owner = q.front();
q.pop();
}
qLock.releaseLock();
} else {
throw runtime_error("Mutex can't release");
}
}
};
TheLock lock;
int g = 0;
void* run(void* pt) {
int id = (int) pt;
for (int i = 0; i < 10000; i++) {
lock.getLock(id);
//cout<<"Thread "<<id<<" get lock, g="<<g<<endl;
int next = g + 1;
g = next;
//cout<<"Thread "<<id<<" release lock, g="<<g<<endl;
lock.releaseLock(id);
}
return NULL;
}
int main() {
pthread_t th[Tcount];
long mtime, seconds, useconds;
struct timeval start, end;
gettimeofday(&start, NULL);
for (int i = 0; i < Tcount; i++) {
pthread_create(&th[i], NULL, run, (void*) (i+10));
}
for (int i = 0; i < Tcount; i++) {
pthread_join(th[i], 0);
}
gettimeofday(&end, NULL);
seconds = end.tv_sec - start.tv_sec;
useconds = end.tv_usec - start.tv_usec;
mtime = ((seconds) * 1000000 + useconds);
cout << "g=" << g << endl;
cout << "time=" << mtime << endl;
return 0;
}
You cannot implement a mutex by using the volatile keyword as the operations may not be atomic. This means that the OS might switch to a different thread before the operation has completed.
For mutex you have to use the OS. It is the only thing that knows when threads are being switched.

pthreads SIGHUP on Simple Linux Timer

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.