LINUX.ORG.RU

sched_yield не работает?


0

1

Столкнулся с такой проблемой. Есть многопоточная программа. Один из тредов работает по следующему циклу: 1. Залочить мьютекс 2. Поработать 3. Отдать мьютекс 4. sched_yield, т.к. после этого выполятеся 1, т.е. мьютекс бы сразу залочился, что не дало бы возможности поработать другому треду

Но недавно на одной из систем обнаружил, что sched_yield не отрабатывает, как ожидается. Т.е. другой поток перехватывает мьютекс только, если ему очень повезет.

Пока, как временное решение, заменил на usleep(1).

В инете нашел, что вроде как и вправду не на всех ядрах этот вызов работает, как следует... Может, аналитики ЛОРа просветят более подробно?

★★

sched_yield не гарантирует, что следующим запуститься твой второй поток. он просто завершает тайм-слайс текущего потока, решение, какой поток выполнять дальше, выполняет планировщик. при этом он вполне может выбрать даже тот же поток.

val-amart ★★★★★
()

очень плохая музыкаое решение. если нужна синхронная работа - используй два семафора.

mi_estas
()

Вы не понимаете, как работает sched_yield. Он делает ровно то, что и должен делать. Просто сама семантика sched_yield не имеет четкого смысла (если только для процесса не установлен планировщик SCHED_RR). Вам следует четко понять, чего вы хотите добиться и выбрать соответствующий механизм синхронизации.

dmitry_vk ★★★
()
Ответ на: комментарий от val-amart

>при этом он вполне может выбрать даже тот же поток.

Если используется планировщик CFS, то это очень даже вероятно.

dmitry_vk ★★★
()
Ответ на: комментарий от cattail

На линухах он всегда 0 возвращает. Так в манах написано, да я другого и не видел

kulti ★★
() автор топика
Ответ на: комментарий от mi_estas

Нужно, чтобы один тред почти постоянно владел ресурсом, но в то же время, другой мог бы легко его получить. Поэтому мы так и делали: лочили, немного работали, возвращали, пытались переключить поток...

kulti ★★
() автор топика

Посмотри в сырцах, там когда CFS прикручивали что-то мудрили с этим системным вызовом. Как минимум я вижу архивы lkml на эту тему.

true_admin ★★★★★
()
Ответ на: комментарий от kulti

> в манах написано, что он переставляет текущий поток в конец очереди планирования

Это была деталь реализации, на которую не следовало полагаться. И, наверное, старые маны.

tailgunner ★★★★★
()
Ответ на: комментарий от kulti

> переставляет текущий поток в конец очереди планирования

Если включишь планировщик FIFO, то так и должно быть. В дефолтном планировщике никто не обещает наличие очереди вообще :)

const86 ★★★★★
()
Ответ на: комментарий от const86

Лучше что-бы тред висел на семафоре и ждал сигнала от другого треда, когда ему можно проснутся и работать. То есть добавить туда события через sem_post()/sem_wait().

sn1ln
()
Ответ на: комментарий от kulti

Соединение с БД. libpqxx мы используем

Можно попробовать использовать condition'ы.

man pthread_cond_wait, pthread_cond_signal, pthread_cond_broadcast или их аналоги в уже используемой библиотеке (типа boost), если что-то используете.

mv ★★★★★
()
Ответ на: комментарий от kulti

я бы придумал какой-нибудь сигнализатор, сразу в голову правда ничего особенного не приходит кроме cond_wait & cond_signal, думать надо. да и вооще

Нужно, чтобы один тред почти постоянно владел ресурсом, но в то же время, другой мог бы легко его получить.

ты не находишь здесь противоречия? думаю «легко» не получится.

mi_estas
()

Понятно, значит sched_yield и правда кака... Придется по другому задачу решать.

Если у кого-нибудь идеи есть, буду рад. Задача такая: Есть соединение с БД. Первый тред слушает события постгреса(NOTIFY). Для этого ему нуже коннекшен. Но этот же коннекшен может понадобится в другом треде, чтобы select сделать. Т.е. получается, что первый тред взял ненадолго коннекшен, проверил, есть ли NOTIFY от постгреса, и вернул коннекшен. Если он никому не нужен, то опять взял его себе и проверил наличие notify.

В общем, мысль у меня сейчас такая: обложить мьютексом не сам коннекшен, а некую переменную dbConnectionUsed и с делать wait/signal

kulti ★★
() автор топика
Ответ на: комментарий от kulti

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

val-amart ★★★★★
()
Ответ на: комментарий от arsi

Что такое LISTEN/NOTIFY в PostreSQL знаешь? Вот чтобы колбэки внутри программы дергать, когда случился евент, первый тред и нужен

kulti ★★
() автор топика
Ответ на: комментарий от kulti

В общем, вот, набросал на коленке. Вроде как работает, может, кому пригодится:

  template <class T>
  class resource_holder
  {
    public:
      resource_holder(T* r = NULL) : _resource(r), _is_used(false){}

      void reset(T* nr)
      {
        _resource.reset(nr);
      }

      T* get()
      {
        _mtx.lock();
        if( _is_used )
          _cond.wait(_mtx);
        _is_used = true;
        _mtx.unlock();

        return _resource.get();
      }

      void free()
      {
        _mtx.lock();
        _is_used = false;
        _cond.notify();
        _mtx.unlock();
      }

    private:
      mutex _mtx;
      cond _cond;
      std::auto_ptr<T> _resource;
      bool _is_used;
  };

kulti ★★
() автор топика
Ответ на: комментарий от kulti

Хотя нет... та же проблема, хоть и значительно реже. Видимо, так и придется оставить костылик в виде usleep(1)

kulti ★★
() автор топика
Ответ на: комментарий от kulti

Сделай прокси объект. Когда надо с базой работать - он просто дублирует команды, а когда приходять уведомления, он сигнализирует тем, кто подписан. Тривиально не получится, зато будет работать.

mi_estas
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.