c++ - pthreads SIGHUP on Simple Linux Timer

标签 c++ linux pthreads

运行时间:

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$ 

我正在尝试编写一个在后台线程上运行并使用 gettimeofday(3) 函数和用户指定回调函数的计时器类。这将在我正在从 Windows 移植到 Linux 的 OpenGL 应用程序中使用。

当我运行这段代码时(见下文)。在 Release模式下运行时,我的线程挂起。但是,当我使用调试器逐步执行代码时,一切似乎都运行良好。这对我来说是一个时间问题。我对此可能是错误的,因为我刚刚学习如何使用线程。有人可以帮助我理解为什么我的线程应用程序从操作系统获取此信号吗?

有两个地方可以得到代码,你可以从我的trac网站下载: Trac Site

或者您可以直接复制粘贴:

主要.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);
}

最佳答案

好吧,你的析构函数肯定坏了。当另一个线程可能正在使用它时,您不能销毁它。当另一个线程可能正在访问它时,您不能修改 m_bRunning。你想要:

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);
}

你有很多并发错误。例如,您的 addTimer 函数修改共享的 m_timers 结构而不持有互斥体。

关于c++ - pthreads SIGHUP on Simple Linux Timer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9147027/

相关文章:

c++ - 使用Android NDK在constexpr构造函数(c++ 17)中分配给const char *失败

C++ 如何编写一个不是成员函数的运算符?

c++ - 解决我列表中的 C++ 类模板错误

Linux:按具有相同值的列合并行

linux - 在 unix 远程服务器中执行参数文件

c - Pthread I/O 缓冲区 : Why doese it print a redundant line?

c++字符串到char *的隐式转换匹配错误的函数签名

linux - 如何通过性能测试中性能低的机器来计算算法在高性能机器上的性能?

线程可以修改 pthread_create 参数吗?

debugging - 带pthread的电子围栏