На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (6) [1] 2 3 ...  5 6 все  ( Перейти к последнему сообщению )  
> Распараллеливание выполнения без блокировок
    Всем привет!

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

    Вот получилась такая у меня прога. Пример чисто синтетический. Одна нить чего-то генерирует (в данном случае std::string), кладет генерируемое в разделяемый стек. А основная нить программы опрашивает стек, и если видит хотя бы один элемент - забирает его из стека и печатает содержимое того, чего забрала.

    Сама прога:
    Скрытый текст
    ExpandedWrap disabled
      #include <functional>
      #include <iostream>
      #include <string>
      #include <memory>
      #include <atomic>
      #include <chrono>
      #include <thread>
      #include <ctime>
       
      #if defined(_WIN32)
      #include <conio.h>
      #elif defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
      #include <cstdio>
      #include <sys/select.h>
      #include <sys/ioctl.h>
      #include <termios.h>
       
      int _kbhit() {
        static const int STDIN = 0;
        static bool initialized = false;
        if (!initialized) {
          termios term;
          tcgetattr(STDIN, &term);
          term.c_lflag &= ~(ICANON | ECHO);
          tcsetattr(STDIN, TCSANOW, &term);
          setbuf(stdin, NULL);
          initialized = true;
        }
        int bytesWaiting;
        ioctl(STDIN, FIONREAD, &bytesWaiting);
        return bytesWaiting;
      }
      #else
      #error "На тостере не работаю!"
      #endif
       
      using namespace std::chrono_literals;
       
      template <typename T>
      struct Node {
        std::shared_ptr<T> Data;
        Node* Next;
        Node(T const& iData): Data(std::make_shared<T>(iData)) {  }
      };
       
      template <typename T>
      class FreeStack {
          std::atomic<Node<T>*> Head;
        public:
          void Push(T const& iData) {
            Node<T>* const NewNode = new Node<T>(iData);
            NewNode->Next = Head.load();
            while (!Head.compare_exchange_weak(NewNode->Next, NewNode));
          }
          std::shared_ptr<T> Pop() {
            Node<T>* OldHead = Head.load();
            while (OldHead && !Head.compare_exchange_weak(OldHead, OldHead->Next));
            return OldHead ? OldHead->Data : std::shared_ptr<T>();
          }
      };
       
      class WriterThread {
          std::atomic_bool& RunFlag;
          std::atomic_bool& DoneFlag;
          FreeStack<std::string>& Stack;
          WriterThread() = delete;
        public:
          explicit WriterThread(std::atomic_bool& iRunFlag, std::atomic_bool& iDoneFlag, FreeStack<std::string>& iStack):
            RunFlag(iRunFlag), DoneFlag(iDoneFlag), Stack(iStack) {}
          void operator()() const {
            int cnt = 0;
            std::srand(unsigned(std::time(0)));
            while (RunFlag) {
              cnt++;
              uint32_t Sleep = 500 + (std::rand() % 1000);
              std::this_thread::sleep_for(std::chrono::milliseconds(Sleep));
              std::string Tmp = std::to_string(cnt) + " : " + std::to_string(Sleep) + " : writer string";
              Stack.Push(Tmp);
            }
            DoneFlag = true;
            std::cout << "Writer is over..." << std:: endl;
          }
      };
       
      class ReaderThread {
          std::atomic_bool RunFlag = true;
          std::atomic_bool DoneFlag = false;
          FreeStack<std::string> Stack;
        public:
          ReaderThread() {}
          void Run() {
            WriterThread Writer(RunFlag, DoneFlag, Stack);
            std::thread Thread(Writer);
            Thread.detach();
            while (!_kbhit()) {
              std::shared_ptr<std::string> Tmp = Stack.Pop();
              if (Tmp) {
                std::cout << *(Tmp.get());
                std::cout << std::endl;
              }
            }
            std::cout << "A key was pressed..." << std:: endl;
            RunFlag = false;
            while (!DoneFlag) {
              std::cout << "Waiting for a completion of the detached thread..." << std:: endl;
              std::this_thread::sleep_for(std::chrono::milliseconds(50));
            }
          }
      };
       
      int main() {
        ReaderThread Reader;
        Reader.Run();
        std::cout << std::endl;
        std::cout << "Bye-bye!" << std::endl;
        return 0;
      }

    А вот примерный вывод после работы проги:
    Скрытый текст
    ExpandedWrap disabled
      1 : 591 : writer string
      2 : 634 : writer string
      3 : 827 : writer string
      4 : 751 : writer string
      5 : 954 : writer string
      6 : 947 : writer string
      7 : 815 : writer string
      8 : 625 : writer string
      9 : 642 : writer string
      A key was pressed...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Writer is over...
       
      Bye-bye!

    Собственно прошу критики.

    1) Где какие ошибки я допустил?
    2) В каких местах имеет смысл ловить и обрабатывать исключения?
    3) По скольку отдельная нить не заточена на вычисления, а скорее на ожидания - какой интервал опроса имеет смысл оставить, чтобы попусту не грузить систему?

    А я пока посмотрю, как обстоят дела с QThread. Читал, вроде там сигналы-слоты реализованы потоко-безопасно. Может вообще не придется городить разделяемый стек, а данные передавать прямо в сигнале.

    Добавлено
    Цитата JoeUser @
    1) Где какие ошибки я допустил?

    Пока сам нашел одну логическую ошибку в ReaderThread::Run(). А именно... В потенциале, между нажатием клавиши и ожиданием завершения потока, вполне еще может что-то шлепнуться на вершину стека. А в нынешней реализации - оно оттуда не забирается. Буду переписывать этот метод! :(
    ...

    И точно - я не ошибся !!! :)

    Вот новый код метода ReaderThread::Run()

    ExpandedWrap disabled
      void Run() {
        WriterThread Writer(RunFlag, DoneFlag, Stack);
        std::thread Thread(Writer);
        Thread.detach();
        while (true) {
          if (_kbhit() && RunFlag) {
            std::cout << "A key was pressed..." << std:: endl;
            RunFlag = false;
          }
          if (!RunFlag && !DoneFlag)
            std::cout << "Waiting for a completion of the detached thread..." << std:: endl;
          std::shared_ptr<std::string> Tmp = Stack.Pop();
          if (Tmp) {
            std::cout << *(Tmp.get());
            std::cout << std::endl;
          } else {
            if (DoneFlag)
              break;
          }
        }
      }

    А вот вывод "с дочисткой стека":
    ExpandedWrap disabled
      1 : 1352 : writer string
      2 : 1042 : writer string
      3 : 582 : writer string
      4 : 595 : writer string
      5 : 1203 : writer string
      6 : 1347 : writer string
      7 : 1483 : writer string
      A key was pressed...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Waiting for a completion of the detached thread...
      Writer is over...
      8 : 625 : writer string
       
      Bye-bye!
      Цитата
      Распараллеливание выполнения без блокировок

      Сразу забудьте. Это не Ваш случай.

      По поводу QT проблемы с глобальными сиглтонами из-за параллельной сборки он в исполняемые файлы пихает несколько штук. Пришлось через разделяемую память делать свой синглтон и на основе него мьютексы для блокировок.
      Сообщение отредактировано: Pavia -
        Цитата Pavia @
        Сразу забудьте. Это не Ваш случай.

        Так не пойдет! Или обоснование и объяснение, или сей коммент - в трэш.

        Цитата Pavia @
        По поводу QT проблемы с глобальными сиглтонами из-за параллельной сборки он в исполняемые файлы пихает несколько штук.

        Pavia, ты что издеваешься?! >:( Компиляция может быть параллельной (есть ключи типа -jN), но сборка (окончательная линковка) тут при чем? Более того ... "Глобальные синглтоны" чего??? И почему не может быть несколько разных синглтонов? И тут же ... или обоснования и объяснения, или сей коммент - в трэш.

        M
        Я сразу обозначу свою позицию. Если обоснований не будет - я расценю твой коммент как типа "на поржать" над новичком.
        А если это будет так - впилю форумное наказание по максимуму. Если это не де жа вю, то подобного качества коменты от
        тебя на моей памяти уже второй раз. Тебе сутки!
          M
          Не поленился и поискал тот коммент, который был де жа вю  - вот он.
          Который так и остался "пшиком" без объяснения и аргументации.
            JoeUser
            Цитата JoeUser @
            ты что издеваешься?! Компиляция может быть параллельной (есть ключи типа -jN), но сборка (окончательная линковка) тут при чем?

            Я вам рассказал про подводные камни. А что с ними делать это вам решать.

            Цитата
            "Глобальные синглтоны" чего??? И почему не может быть несколько разных синглтонов?

            Синглтон в переводи на русский одиночка. Он по своей природе один. А вот интерфейсов у него может быть много. Короче RTFM.

            Цитата
            Так не пойдет! Или обоснование и объяснение, или сей коммент - в трэш.

            А что обосновывать? Атомарные операция это тоже блокировка 50-180 тактов в зависимости от процессора. И также приводит LiveLock(разновидность DeadLock)
              Цитата Pavia @
              А что обосновывать? Атомарные операция это тоже блокировка 50-180 тактов в зависимости от процессора.

              Атомарные операции в трактовке С++, операции "без блокировки". Что творится на уровне команд процессора/ОС - это уже раздел уровнем ниже, типа "ASM". Но мы общаемся в терминах Стандарта С++ и его терминологии.

              Цитата Pavia @
              Сразу забудьте. Это не Ваш случай.

              На это утверждение так и нет обоснования! Жду.

              Цитата Pavia @
              Синглтон в переводи на русский одиночка. Он по своей природе один. А вот интерфейсов у него может быть много. Короче RTFM.

              Только ненадо RTFM'ами кидаться. Я прекрасно знаю что такое Синглтон. Я просто прошу обосновать, а желательно и привести пример по вот этому утверждению:

              Цитата Pavia @
              По поводу QT проблемы с глобальными сиглтонами из-за параллельной сборки он в исполняемые файлы пихает несколько штук.

              Опять жду обоснования и пример.

              Цитата Pavia @
              Я вам рассказал про подводные камни.

              Пока только голые утверждения, нет ни конкретики, ни примеров!

              Добавлено
              Цитата Pavia @
              И также приводит LiveLock(разновидность DeadLock)

              Кстати ... и тут пруф какбэ нужен! Иначе это из разряда догадок.

              Добавлено
              Цитата Pavia @
              И также приводит LiveLock

              Теоретически да - в 0.00000000000001% случаев, когда две операции выполняют однотипные по тактам операции. Но когда один поток зависит от готовности "периферии", а второй просто чекает флаг - это утверждение приобретает ценность размышлений о жизнедеятельности сферического коня в вакууме!
                Цитата JoeUser @
                1) Где какие ошибки я допустил?

                1) Вместо std::thread - используй std::future в связке с async (это следует делать в 95% случаях, по крайней мере так советует Майерс, и я ему верю, хотя некоторые не согласны с этим утверждением, но все же) - потому что std::thread имеют кучу подводных камней(читай Майерса)
                2) Вместо std::atomic<ololo> flag - используй conditial variables.
                3) Тебе точно нужен вот этот стек, может лучше очередь ? В любом случае твой стек выглядит весьма странно, какие то циклы внутри, я так понимаю это что то типа примитивных неблокирующих средств синхронизации? Я бы юзал всеже conditional_variables, они туда больше подходят.

                Какой стандарт плюсов ты используешь? В С++17 завезли, ЕМНИП, алгоритмы для паралельных вычислений и возможно многопоточные структуры данных, я б изучил сперва, что есть в языке.

                Цитата JoeUser @
                2) В каких местах имеет смысл ловить и обрабатывать исключения?

                В твоем случае необходимо юзать std::future и почитать как обрабатывать исключения из него(У Майерса все это есть.)

                Цитата JoeUser @
                3) По скольку отдельная нить не заточена на вычисления, а скорее на ожидания - какой интервал опроса имеет смысл оставить, чтобы попусту не грузить систему?

                Юзать conditional variable. Ну и вообще я бы на твоем месте почитал про схему Producer -> Consumer, в многопоточном программировании. У тебя же один Consumer ? Тогда можно одной conditional_variable обойтись.

                Ну и еще я бы почитал на твоем месте, хотя бы по диагонали Майерса(Скот Майерс "Эффективный и современный C++") и книгу про многопоточность в последнем стандарте. Но из последнего в принципе подойдет и "Энтони Уильямс - Параллельное программирование на С++ в действии."

                Добавлено
                Цитата JoeUser @
                Вот новый код метода ReaderThread::Run()

                Если что, все вот эти std::cout - глобальные переменные, а не просто абы что. Я к тому, что обычно такие вещи пишутся с блокировками.
                Сообщение отредактировано: Wound -
                  Wound, мы с тобою как будто из разных вселенных! :lol:

                  Я код не просто из башки взял. Я изучил книгу Энтони Уильямса "Прараллельное программирование в действии". И "структуры без блокировок" взял оттуда, почти один-в-один, ну или почти, только мои "расширения", скажем так. Нахрена мне другая модель параллелизма, к примеру с std::future? Тем более std::future - это ожидание результата асинхронной операции. Но это не мой случай. У меня нет результата асинхронной операции! У меня есть просто асинхронное исполнение второго потока, результаты которого нужно юзать время от времени (по факту готовности).

                  Цитата Wound @
                  Вместо std::atomic<ololo> flag - используй conditial variables.

                  А вот тут не вижу профита совсем. Если у меня неблокируемое ожидание, чем мне поможет std::condition_variable? Да вообще ничем! Будет просто другой синтаксис, но отдача квантов вычисленя CPU при ожидании останется равной. Так нахрена коту баян?

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

                  Давай договоримся так, ты указываешь мне как надо делать в моем коде в плане исправления ошибок (или просто где ошибки), но не указываешь как изменять архитектуру кода. Не учишь меня жизни сейчас (я сам когда-то если и обломаюсь, то научусь). А я тебе скидываю скан книги Энтони Уильямса "С++ Concurrency in Action" в русском переводе. Только скажи как и куда?

                  Скрытый текст
                  Энтони Уильямс. Параллельное программирование в действии. Практика разработки многопоточных программ. Пер с англ.Слинкин A.A. - M: ДМК Пресс, 2012.-627c.:ил. ISBN 978-5-94074-448-1
                    Цитата Wound @
                    Если что, все вот эти std::cout - глобальные переменные, а не просто абы что. Я к тому, что обычно такие вещи пишутся с блокировками.

                    Хм :-? ... Принято!!! Пруф?
                      Цитата Wound @
                      Но из последнего в принципе подойдет и "Энтони Уильямс - Параллельное программирование на С++ в действии."

                      :yummy:

                      Все мои нынешние "знания" - исключительно из этой книги. И про "структуры, свободные от блокировок" - тож все оттуда. Я ее перечитал вдоль и поперек, и до сих пор перечитываю. Оч толковый автор, который не просто толкает тему, но и останавливается на мелочах. Важных мелочах. А как говорят "Диавол кроется в мелочах". Вот там то мы его найдем и прихлопнем мухобойкой. Ибо нехрен!

                      Добавлено
                      Цитата Wound @
                      кучу подводных камней

                      Если не сложно, просто перечисли. А я сравню со своей ситуацией, коснется ли меня оно.
                        Цитата JoeUser @
                        Я код не просто из башки взял. Я изучил книгу Энтони Уильямса "Прараллельное программирование в действии". И "структуры без блокировок" взял оттуда, почти один-в-один, ну или почти, только мои "расширения", скажем так.

                        Ну да и на пустом месте нафигачил кучу какого то непонятного кода. ИМХО, тут можно сделать более понятно безо всяких флагов.

                        Цитата JoeUser @
                        Нахрена мне другая модель параллелизма, к примеру с std::future? Тем более std::future - это ожидание результата асинхронной операции. Но это не мой случай. У меня нет результата асинхронной операции! У меня есть просто асинхронное исполнение второго потока, результаты которого нужно юзать время от времени (по факту готовности)

                        Ну хотя бы затем, чтобы нормально обрабатывать исключения. Плюс ко всему избежать косяков detach/join у потока, которые имеют место быть, ну и для того, что подход на основе задач - более гибкий, т.к. ты предоставляешь возможность системе самой решить что и как необходимо использовать. Во многих случаях она лучше тебя знает как и что следует юзать.

                        Цитата JoeUser @
                        А вот тут не вижу профита совсем. Если у меня неблокируемое ожидание, чем мне поможет std::condition_variable? Да вообще ничем! Будет просто другой синтаксис, но отдача квантов вычисленя CPU при ожидании останется равной. Так нахрена коту баян?

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

                        Цитата JoeUser @
                        Киля, я внимательно прочел твой пост. И понял одно - ты меня хочешь притянуть за уши к блокировкам на основе мьютексов. Но, поверь, это не мой вариант. Это и первое, что мне пришло в голову. Но я специально изучил главу "Структуры, свободные от блокировок", чтобы обойтись без локов в угоду атомарным операциям.

                        Ну ты себе только говоной боли наберешься в последствии. Во первых самый лучше способ уйти от блокировок - это избавится от общих ресурсов. А у тебя они есть.

                        Цитата JoeUser @
                        Давай договоримся так, ты указываешь мне как надо делать в моем коде, а указываешь что у меня в потенциале, в моем коде, должно глючить (где и почему). Но не учишь меня жизни сейчас (я сам когда-то если и обломаюсь, то научусь). А я тебе скидываю скан книги Энтони Уильямса "С++ Concurrency in Action" в русском переводе. Только скажи как и куда?

                        В принципе можешь делать как хочешь. Но я бы на твоем месте все же Майерса почитал. Например:
                        Цитата

                        Подход на основе задач обычно превосходит свой аналог на основе потоков, и небольшие
                        фрагменты кода, с которыми вы встретились выше, показывают некоторые причины этого.
                        Здесь doAsyncwork дает возвращаемое значение, в котором, как мы можем разумно предположить, заинтересован вызывающий doAsyncwork код. В случае вызова на основе потоков
                        нет простого способа к нему обратиться. При подходе на основе потоков нет простого способа получить доступ к вызову. В случае же подхода на основе задач это можно легко сделать,
                        поскольку фьючерс, возвращаемый std : : async, предлагает функцию get. Эта функция get
                        еще более важа, если doAsyncwork генерирует искючение, поскольку get обеспечивает доступ и к нему. При подходе на основе потоков в случае генераии функцией doAsyncWork
                        исключения програма аварийно завершается (с помощью вызова std: : terminate).
                        Более фундаментаьным различием между подходаи на основе потоков и на основе задач является воплощение более высокого уровня абстракции в последнем. Он освобождает
                        вас от деталей уравления потоками, что, кстати, напомнило мне о необходимости рассказать о трех значениях слова поток (tread) в параллельном программировании на С++

                        У std::thread - есть косяки с join/detach, по хорошему его нужно оборачивать в класс. Возможно это не твой случай, но все же. Исключения, которые ты не поймал внутри потока - ты больше нигде и никак не сможешь обработать - утечка ресурсов. Используешь ты их примитивно, потому как использование std::thread - обосновано, когда ты хочешь полностью контролировать работу потока вручную! Ты же ее в своем коде никак не контролируешь от слова совсем, даже приоритет не выставляешь.

                        Цитата JoeUser @
                        Хм ... Принято!!! Пруф?

                        Пруф чего именно?
                        Допустим, вот в этом куске кода:
                        Цитата JoeUser @
                        std::cout << "Waiting for a completion of the detached thread..." << std:: endl;

                        на самом деле происходит не атомарный вывод на консоль, а происходит вызов двух независимых друг от друга функций, между которыми - может быть выполнена некоторая другая задача в другом потоке.
                        Я тебе все это уже рассказывал вроде как. Ссылку поискать где?

                        Добавлено
                        Цитата JoeUser @
                        Если не сложно, просто перечисли. А я сравню со своей ситуацией, коснется ли меня оно.

                        Я тебе перечислю ситуации, когда следует использовать std::thread, так понятней наверно будет, вот из книги Майерса:
                        Цитата

                        Тем не менее существуют ситуации, в которых применение потоков
                        может быть более подходящим. Они включают в себя следующее.
                        • Вам нужен доступ к API, лежащей в основе реализации потоков. В С++ API паралельных вычислений обычно реализуется с помощью низкоуровневого платформозависимого API, обычно pthreads или Windows Threads. Эти API в настоящее время
                        предлагают больше возможностей, чем С++. (Например, С++ не имеет понятий приоритетов или родственности потоков.) Для предоставления достуа к API реализации
                        потоков std : : thread обычно предагает функцию-член nat ive_handle. Така функциональность отсутствует в std : : future (т.е. в том, что возвращает std : : async).
                        • Вам требуется возможность оптимизации потоков в вашем приложении. Это может произойти, наример, если вы разрабатываете серверно программное обеспечение с известным профилем выполнения, которое может быть развернуто как единственный процесс на машине с фиксированными аппаратными характеристиками.
                        • Вам требуется реализовать поточную техолоrию, выходящую за рамки API параллельных вычислений в С++, например пулы потоков на платформах, на которых ваши реализации С++ их не предоставляют.
                        Однако это нестандартные ситуации. В большинстве случаев вы должны выбирать
                        программирование на основе задач, а не на основе потоков.
                        Сообщение отредактировано: Wound -
                          А зачем самому lock-free алгоритмы писать? Поверь, это либо просто и с кучей подводных камней, либо сложно и нетривиально. Куда лучше взять какой-нибудь libcds и юзать lock-free хоть очередь хоть стек хоть map.

                          Добавлено
                          Цитата Wound @
                          Упростит немного код и избавит от лишних флагов, которые только запутывают

                          У него изначальное ТЗ - сделать без блокировок, так что cv пролетает мимо.
                            Цитата OpenGL @
                            У него изначальное ТЗ - сделать без блокировок, так что cv пролетает мимо.

                            Да это у него не тз такое, это он сам себе втемяшил что надо делать именно так и никак иначе. А теперь говорит - не учи меня писать, я обчитался книг и теперь хочу писать именно так и никак иначе. :-?

                              censored
                              M
                              Q: оффтоп, JoeUser. К чему тут этот переход на личность?

                              Цитата Wound @
                              Плюс ко всему избежать косяков detach/join у потока

                              What??? :blink: Где, покажи в коде!!!

                              Цитата Wound @
                              на самом деле происходит не атомарный вывод на консоль

                              Киля, ну это же говно!!!
                              Вместо std::cout << "Waiting for a completion of the detached thread..." << std:: endl; я могу написать std::cout << "Waiting for a completion of the detached thread...\n"; это такая мелочь для синтетического примера. Хотя, да, ты тут прав.

                              Цитата Wound @
                              Цитата
                              Однако это нестандартные ситуации. В большинстве случаев вы должны выбирать
                              программирование на основе задач, а не на основе потоков.

                              Вот тут я с Меерсом согласен! Нах натягивать сову на глобус. Если задача ясна, архитектура ясна, зачем архитектуру плющить под детские примеры С++, если можно С++ использовать в полной мере для реализации задуманной архитектуры. Вопрос риторический, есличо.

                              Добавлено
                              Цитата OpenGL @
                              А зачем самому lock-free алгоритмы писать?

                              А у меня тривиальный стек - так почему бы и нет?
                              Или лучше обложиться мьютексами ... так сказать - для надежности? :lol:

                              Добавлено
                              Цитата Wound @
                              Да это у него не тз такое, это он сам себе втемяшил что надо делать именно так и никак иначе. А теперь говорит - не учи меня писать, я обчитался книг и теперь хочу писать именно так и никак иначе.

                              Киля, при всем уважении, ты не лучше всегда знаешь что я хочу.
                              Иногда я хочу лучше чем ты можешь за меня хотеть! 8-)

                              Добавлено
                              Цитата Wound @
                              втемяшил что надо делать именно так и никак иначе

                              Да, и кстати, анука обоснуй ... если есть возможность реализовать структуры без блокировок, зачем "мне твое иначе" (с блокировками)? Обоснуй профит!
                              Сообщение отредактировано: Qraizer -

                                offtop was censored
                                Цитата JoeUser @
                                What??? Где, покажи в коде!!!

                                Ну ты ж отцов то читать не хочешь. Мне тебе сюда всю книгу цитировать или как?

                                M
                                Q: читать отцов – это хорошо. Но ради синтетического простого примера тратить время на гугление материалов, их освоение и осознания идей и концепций никто ожидаемо не будет. Если хочешь заинтересовать оппонента, не надо отправлять в поиск не_знаю_куда, с его точки зрения, не_знаю_чего не_знаю_зачем_мне_якобы_нужного.


                                Цитата JoeUser @
                                Киля, ну это же говно!!!
                                Вместо std::cout << "Waiting for a completion of the detached thread..." << std:: endl; я могу написать std::cout << "Waiting for a completion of the detached thread...\n"; это такая мелочь для синтетического примера. Хотя, да, ты тут прав.

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

                                Цитата JoeUser @
                                Да, и кстати, анука обоснуй ... если есть возможность реализовать структуры без блокировок, зачем "мне твое иначе" (с блокировками)? Обоснуй профит!

                                С блокировками оно надежнее, особенно когда у тебя есть расшаренный ресурс. Сегодня у тебя один продьюсер и один потребитель. Завтра может быть несколько потребителей, а после завтра - появятся несколько продьюсеров и несколько потребителей. И будешь ты переписывать свой код от начала и до конца, либо мудохаться с lock-free флагами как у тебя.
                                Сообщение отредактировано: Qraizer -
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (6) [1] 2 3 ...  5 6 все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0712 ]   [ 16 queries used ]   [ Generated: 25.04.24, 08:31 GMT ]