html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

Pthread_cond_timedwait: проблема, решение, дискуссия recovery mode

Здравствуйте, уважаемые Хабраюзеры!

Продолжая серию постов по многопоточному программированию, хочется коснуться одной фундаментальной проблемы использования сигнальных переменных в Linux, к сожалению, не имеющей пока красивого универсального решения (а может оно просто неизвестно мне). Многие, к сожалению, даже не догадываются о том, что такая проблема имеет место быть.

Рассмотрим простой пример использования сигнальной переменной:

struct timeval now;
struct timespec timeout;
gettimeofday(&now, 0);
timeout.tv_sec = now.tv_sec + 2;      // 2 sec
timeout.tv_nsec = now.tv_usec * 1000; // nsec

retval=0;
pthread_mutex_lock(&mutex);
while(!somethingHappens() && retval==0)
{
    retval=pthread_cond_timedwait(&condition, &mutex, &timeout);
}
pthread_mutex_unlock(&mutex);


Смысл использования pthread_cond_timedwait состоит в том, что мы либо дожидаемся получения сигнала (pthread_cond_signal или pthread_cond_broadcast) в качестве уведомления о том, что somethingHappens(), или же прекращаем ожидание по истечении заданного нами таймаута. Во второй части фразы и кроется та самая потенциальная проблема! Обратите внимание, что время, передаваемое в качестве третьего параметра в pthread_cond_timedwait, задается в абсолютном виде! А что, если время будет переведено назад(!) после того, как мы получим текущее время (gettimeofday) и до того, как уснем в ожидании на pthread_cond_timedwait?

Каково будет поведение pthread_cond_timedwait, если наш процесс уже спит на этом вызове? Здесь все чисто! На всех платформах, на которых я проводил эксперимент с переводом времени назад, изменение просто игнорировалось, т.е. реально внутри вызова время все-таки преобразуется из абсолютного к относительному значению. Интересно, почему это не вынесено в интерфейс функции? Это бы решило все проблемы!

Критики могут возразить, что это какая-то пренебрежимо маловероятная ситуация, чтобы перевод системного времени попал именно в этот ничтожно малый кусок кода. Позвольте не согласиться. С одной стороны, если вероятность какого-либо события не равна нулю, то оно обязательно случится (принято называть это «генеральским эффектом»), а с другой стороны все сильно зависит от конкретной программы. Мы столкнулись с этой проблемой при разработке системы видеонаблюдения, а это десятки потоков (thread-ов), в каждом из которых делается pthread_cond_timedwait раз эдак 25 в секунду, а перевод времени на час назад приводил к тому, что с вероятностью, близкой к 100%, какой-нибудь поток да и заснет на этот час плюс 1/25 секунды!

Что делать?

Как я уже сказал в начале своего повествования, красивого решения данной проблемы нет, но и не решать ее вовсе, нельзя! В нашей системе мы организовали отдельный поток, назовем его «потоком мониторинга системного времени», который отслеживает «переводы времени назад» и в случае их выявления «будит» все сигнальные переменные. Т.е. по сути, решение предполагает наличие в системе некоторого выделенного менеджера, в котором необходимо зарегистрировать все используемые сигнальные переменные. Получилось что-то такое:

class SystemTimeManager
{
public:
    SystemTimeManager();
    ~SystemTimeManager();

    void registerCond(pthread_mutex_t *mutex, pthread_cond_t *cond);
    void unregisterCond(pthread_cond_t *cond);

private:
    static void *runnable(void *ptr);

private:
    time_t _prevSystemTime;
    pthread_t _thread;
    bool _finish;
    pthread_mutex_t _mutex;
    std::map<pthread_cond_t *, pthread_mutex_t *> _container;
};

SystemTimeManager::SystemTimeManager ():
    _prevSystemTime(time(0)),
    _finish(false)
{
    pthread_mutex_create(&_mutex, 0);
    pthread_create(&_thread, 0, runnable, this);
}

SystemTimeManager::~SystemTimeManager()
{
    _finish=true;
    pthread_join(_thread, 0);
    pthread_mutex_destroy(&_mutex);
}

void SystemTimeManager::registerCond(pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    pthread_mutex_lock(&_mutex);
    _container.insert(std::make_pair(cond, mutex));
    pthread_mutex_unlock(&_mutex);
}

void SystemTimeManager::unregisterCond(pthread_cond_t *cond)
{
    pthread_mutex_lock(&_mutex);
    std::map<pthread_cond_t *, pthread_mutex_t *> it=_container.find(cond);
    if(it!=_container.end())
        _container->erase(it);
    pthread_mutex_unlock(&_mutex);
}

void * SystemTimeManager::runnable(void *ptr)
{
    SystemTimeManager *me=reinterpret_cast< SystemTimeManager *>(ptr);
    while(!_finish)
    {
        If(time(0)<_prevSystemTime)
        {
            pthread_mutex_lock(&me->_mutex);
            for(std::map<pthread_cond_t *, pthread_mutex_t *> it=_container.begin();
                 it!=_container.end(); ++it)
            {
                 pthread_mutex_lock(it->second);
                 pthread_cond_broadcast(it->first);
                 pthread_mutex_unlock(it->second);
            }
            pthread_mutex_unlock(&me->_mutex);
        }
        _prevSystemTime=time(0);
        sleep(1);
    }
}


Теперь нам достаточно создать экземпляр класса SystemTimeManager и не забыть зарегистрировать в нем все используемые нами сигнальные переменные.

В заключение хотелось бы обратить внимание уважаемого сообщества на тему данной статьи «проблема, решение, дискуссия». Проблему, я надеюсь, описал достаточно понятно. Решение описанной проблемы, пусть и не самое элегантное, я привел – надеюсь, оно кому-нибудь будет полезно. Однако последнее – дискуссию — я никак не могу сделать без вас, уважаемые Хабраюзеры. Может быть, у кого-то есть какие-то другие, более элегантные решения данной проблемы?
Читать дальше
Twitter
Одноклассники
Мой Мир

материал с habrahabr.ru

0

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • habrahabr.ru
          • домен habrahabr.ru

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции