pthreads SIGHUP на простом таймере Linux - PullRequest
1 голос
/ 05 февраля 2012

Запуск:

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) плюс указанную пользователем функцию обратного вызова.Использование этого будет в приложении OpenGL, которое я в процессе портирования с Windows на Linux.

Когда я запускаю этот код (см. Ниже).Мои темы зависают при работе в режиме выпуска.Однако, когда я перебираю код с помощью отладчика, кажется, что все работает нормально.Это указывает на временную проблему для меня.Я могу ошибаться по этому поводу, так как я только сейчас учусь использовать потоки.Может ли кто-нибудь помочь мне понять, почему мое потоковое приложение получает этот сигнал от ОС?

Есть два места, где вы можете получить код, вы можете скачать его с моего сайта trac: Trac Site

Или вы можете просто скопировать и вставить:

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

1 Ответ

2 голосов
/ 05 февраля 2012

Ну, твой деструктор определенно сломлен.Вы не можете уничтожить мьютекс, пока другой поток может его использовать.И вы не можете изменить 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 без удержания мьютекса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...