LINUX.ORG.RU

Создание фонового треда на время жизни класса

 


0

2

Идея примерно такая. Есть некоторый класс A в котором есть некоторая струтура данных, допустим мапа. Класс имеет публичные методы работы с этой мапой. Но нам допустим надо запустить фоновый поток который будет в бесконечном цикле проверять, ну допустим насколько запись в мапе стара и удалять ее если надо. Тред должен завершиться вместе с уничтожением класса без ругани и эксепшенов.

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

#include <thread>
#include <memory>
#include <map>
#include <iostream>
typedef  std::map<std::string,std::string> MyMap;

class A
{
private:
  class Thread
  {
  private:
    bool flag;
    MyMap& my_map_inst;
    std::thread thr;
  public:

    void funct()
    {
      while (flag) {
        std::cout << "ooo" << std::endl;
      }
      std::cout << "fin" << std::endl;
    }

    Thread(MyMap& m) : flag(true), my_map_inst(m), thr(std::bind(&Thread::funct,this))
    {
    }

    void final()
    {
      flag = false;
      thr.join();
    }

  };

  MyMap my_map_inst;

  Thread thread_i;
public:
  A() : thread_i(my_map_inst)
  {

  }

  ~A()
  {
    thread_i.final();
  }

};

int main()
{

  {
  A a;

  }
  std::cout << "111" << std::endl;

  int i;
  std::cin >> i;
  return 0;
}

По идее проблем быть не должно. Стандарт вроде гарантирует создание мапы до создания объекта треда и инициализацию контрольного флага (flag) до запуска треда. Может тут есть еще какие подводные камни?

★★★★★

Последнее исправление: Dudraug (всего исправлений: 3)
Ответ на: комментарий от intelfx

А тред так и будет крутиться в busy loop'е, отжирая 100% CPU?

Же

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

Ес-но с неким слипом.

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

Зачем так сложно?

class myclass {
    volatile bool exitflag = false;
    std::map<std::string, std::string> map;
    std::thread thread;

public:
    myclass() : thread([this]() {
            while (!exitflag) {
                std::cerr << "processing" << std::endl;
            }
            std::cerr << "done" << std::endl;
        }) {
    }

    ~myclass() {
        exitflag = true;
        thread.join();
    }
};

Ну и да, естественно в реальном приложении вместо busyloop нужна condition variable, тогда и volatile можно будет убрать.

slovazap ★★★★★
()
Последнее исправление: slovazap (всего исправлений: 1)

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

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

когда к нему обратились - тогда и выбрасывать устаревшие записи.

Время отклика чтения/записи увеличивается. Но вообще как вариант.

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

Запретить оператор= и копирование/мув (хотя мув можно оставить). И вообще в синглтон запихнуть.

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

вьюноша тут только изучил чудеса С++11, успешно загрузил проц на 100%, а вы ему про тонкости использования переменных в кернеле вещаете.

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

успешно загрузил проц на 100%

Давай без сарказма, где там загрузка проца на 100%?

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

Ты то вообще предлагаешь при каждом инсерте/фаинде обходить мапу и чистить ее. Не находишь, что твой подход тоже индуизмом попахивает=)

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

Это было для тех, кто тут пришел советовать volatile для того, для чего оно не предназначено.

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

а зачем его обходить? мап отсортирован по ключу, правильный мап организован в виде связного списка, и в этом его главный плюс. отрезание половины мапа сразу - это одна(!) операция. если мап в пуле, то скорость создания нового элемента просто молниеносная. а чистить пул можно по окончании работы. или в бэкграунде. главная вычислительная задача - найти границу. ты же пока что предлагаешь обходить мап не один раз, а стопицот раз в секунду. и удалять по нескольку элементов, умножая ещё и количество удалений. между тем, количество проверок будет логарифмическим в любом случае.
про загрузку 100% проца - это про вот это вот: Создание фонового треда на время жизни класса (комментарий)
по-моему, там она очевидна, даже компилировать не требуется.

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

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

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

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

Добавляешь слип и 100% нет, слип можно большой добавить.

а зачем его обходить? мап отсортирован по ключу

Что бы узнать нужно ли удалять. Это надо если вставка и поиск производится по одному критерию (ключу), а удалять надо по другому (по данным). Подставь вместо данных(second) не std::string, а любой объект с полями «дата создания» и «срок валидности». Надо поддерживать мапу в актуальном состаяние. Решения я вижу тут только два: 1) запустить бэкграунд тред, который будет чистить ее в n секунд; 2) обходить мапу при поиски/добавление и удалять не нужное. По мне так первый подход намного лучше.

правильный мап организован в виде связного списка, и в этом его главный плюс.

Я всегда думал, что в виде бинарного дерева поиска...

ты же пока что предлагаешь обходить мап не один раз, а стопицот раз в секунду

Нет, я предлагаю сделать слип на n секнуд, скажем на 10 (вообще это не важно на сколько) и чистить ее только один раз в 10 секунд.

главная вычислительная задача - найти границу.

Это если мапа отсортирована по критерию удаления (то есть ключ есть этот критерий). Но это может быть не так.

Да и вообще тред не об этом. Я привел сферический код в вакууме в отрыве от реальной задачи. Возможно я сейчас пилю программу/модуль где это надо, а может и нет. Мне интересны были подводные камни и возможно более изящные решения. Про мапы, деревья и альтернативные варианты я и так в курсе.

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

ну, можно rb-tree

«Ну, можно»? А можно привести пример, когда map реализуется не деревом?

будет чуть быстрее поиск

Поиск на дереве будет «чуть» быстрее, чем на списке? Ты серьезно?

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

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

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

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

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Ответ на: комментарий от Dudraug

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

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

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

Ээээ... неупорядоченная мапа есть в с++11 и она быстрее обычной упорядоченной, ибо хэш-таблица.

был шустрее всех стандартных реализаций

Быстрее std::unordered_map? Пруфы в студию, по идее на хэш-таблице должно быть все примерно одно. Там алгоритм просто до безобразия.

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

А можно привести пример, когда map реализуется не деревом?

boost::flat_map, внутри — отсортированный вектор, со всеми следствиями.

i-rinat ★★★★★
()
Ответ на: комментарий от Iron_Bug

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

Ты сам догадаешься почему связанный список намного хуже чем дерево при поиске?

Dudraug ★★★★★
() автор топика
Ответ на: комментарий от i-rinat

boost::flat_map, внутри — отсортированный вектор, со всеми следствиями.

Ну вектор с точки зрения поиска получше списка, да. Но как там происходит удаление элемента?

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

Пишут, что сдвигом. Не пользовался им никогда, только вчера вообще узнал, что он есть. (Срачи в development — образовательные).

i-rinat ★★★★★
()
Ответ на: комментарий от Dudraug

Быстрее std::unordered_map? Пруфы в студию, по идее на хэш-таблице должно быть все примерно одно. Там алгоритм просто до безобразия.

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

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

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

Речь шла именно об отсортированных:

Iron_Bug> мап отсортирован по ключу

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

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

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

Да мы тут в одном из тредов это уже обсуждали (правда со срачем и кучей бреда). Я хотел даже сравнить std::map и std::unordered_map с графиками в гнуплоте. Но заленился.

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

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

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

иногда неотсортированный мап работает тупо быстрее. смотря что требуется.

Несортированный мап должен всегда работать быстрее, ибо скорее всего это хэш-таблица. Только вот хэш-таблица столько оперативки жрет...

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

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

Iron_Bug ★★★★★
()

Ну давай рассмотрим задачу: 1) Тебе надо постоянно время от времени сканировать структуру данных на предмет чего-либо. 2) Тебе надо завершать твое сканирование без задержек.

http://en.cppreference.com/w/cpp/thread/condition_variable/wait_for

#include <iostream>
#include <thread>
#include <condition_variable>
#include <atomic>
#include <chrono>

class Worker {
  std::mutex mutex;
  std::condition_variable cv;
  std::atomic<bool> finished;
  std::thread workerThread;
public:
  Worker() : finished(false), workerThread([this] { this->run(); }) { }
  void run() {
    std::cout << "started thread\n";
    std::unique_lock<std::mutex> lock(mutex);
    while(!finished) {
      cv.wait_for(lock, std::chrono::milliseconds(1000));
      std::cout << "do things\n";
    }
    std::cout << "finishing\n";
  }
  void stop() {
    finished = true;
    cv.notify_all();
    workerThread.join();
  }
};

int main() {
  Worker w;
  std::cout << "press enter to terminate\n";
  std::cin.get();
  w.stop();
  return 0;
}

invy ★★★★★
()

Сынок, ты уже взрослый, настало время рассказать тебе о std::condition_variable

anonymous
()
Ответ на: комментарий от invy
cv.wait_for(lock, std::chrono::milliseconds(1000));

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

anonymous
()
Ответ на: комментарий от slovazap

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

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