2013-12-02 4 views
1

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

У меня есть базовый объект

class Element 
    { 
    public: 
     int a; 
     float p; 
     Element(int _a, float _p=1.0): a(_a), p(_p){}; 
    }; 

из которых Я создаю вектор и включаю в объект Buffer.

class Buffer 
    { 
    public: 
     Buffer(){}; 

     vector<Element> raw;  
     vector<Element> optimised; // DATA CALCULATED BASED ON RAW 

     void addElement(int _a,float _p=1.0) // FILL THE RAW BUFFER 
     { 
      raw.push_back(Element(_a,_p)); 
     } 

     void compute() // COMPUTE THE OPTIMISED BUFFER 
     { 
      float t; 
      int i; 
      for(std::vector<Element>::iterator it = raw.begin(); it != raw.end(); ++it) 
      { 
       optimised.push_back(Element(it->a,it->p)); 
       // DO SOME COMPUTATIONALLY INTENSIVE CALCULATIONS 
       for(i=1; i<9999999; i++) 
        t = 9./i; 
      } 
     }; 

     void clear() // ERASE BOTH BUFFERS 
     { 
      raw.clear(); 
      optimised.clear(); 
     } 
    }; 

У меня есть заявление одного объекта буфера - отвечает за захват текущего потока данных - и вектор объектов Buffer - ведет себя как историю/очередь из ранее созданных буферов.

Buffer buffer; 
vector<Buffer> queue; 

Основной поток отвечает заполнения объекта буфера и - один раз серия завершена - представить буфер в очередь. Как только новый буфер добавляется в очередь, функция вычисления() вызывается в отдельном потоке для анализа недавно представленных данных.

//ADD THE CURRENT BUFFER TO THE QUEUE 
queue.push_back(buffer); 

//RUN 'COMPUTE' IN PARALLEL/BACKGROUND ON THE LAST SUBMITTED BUFFER 
std::thread t(&Buffer::compute, &queue.back()); 
t.detach(); 

//CLEAR THE BUFFER, READY FOR A NEW SERIES 
buffer.clear(); 

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

Должен ли я использовать замки для мьютексов в этой ситуации? Если да, то где?

Есть ли у вас какие-либо предложения о том, как оптимизировать сбор данных (заполнить объект «буфер» и представить его в очередь) - я думаю, что AddElement() немного излишне дорого?

ЛЮБАЯ ПОМОЩЬ ОЦЕНКА!

Благодаря

+1

Вы, кажется, не выполнять каких-либо синхронизации вообще. Почему нет? –

+0

@DavidHeffernan ОП спрашивает, если это будет необходимо.Ответ определенно Да! –

+0

Можете ли вы дать мне предложение о синхронизации, которую мне нужно сделать? Я пытаюсь использовать мьютекс, но у меня все еще были сбои - если только один буфер/нить не вычисляется за раз. Я думал, что мне не нужно блокировать(), поскольку между потоками нет данных (я копирую буфер в очередь). Мне нужен этот алгоритм, чтобы быть ОЧЕНЬ эффективным и текучим ... –

ответ

2

Проблема с &queue[last]. Это дает вам указатель на то, где вектор в настоящее время хранит буфер. Если вектор перераспределяет (push_back может это сделать), то указатель недействителен.

Есть несколько решений этой: указатель

  • Хранить в queue векторе. Нечто вроде vector<unique_ptr<Buffer>> queue будет работать (и гарантирует, что вы случайно не пропустите память).
  • Использовать структуру данных, которая не приведет к аннулированию указателей при изменении. list и deque будет работать.
  • Убедитесь, что вектор не перераспределяется. Сначала вы можете сделать resize(x), а затем следить за последним самостоятельно.

Обновление: добавьте образец кода. Это компилирует и работает отлично на Coliru (http://coliru.stacked-crooked.com/)

#include <memory> 
#include <vector> 
#include <iostream> 
class Buffer {}; 

int main() 
{ 
    std::unique_ptr<Buffer> buffer {new Buffer()}; 
    std::vector<std::unique_ptr<Buffer>> queue; 
    for (int i = 0; i < 10; i++) { 
     buffer.reset(new Buffer()); 
     // Do things to buffer; 
     queue.push_back(move(buffer)); 
    } 
    std::cout << queue.size() << std::endl; 
} 
+0

cheers .. umh как я могу добавить «buffer» (который имеет тип Buffer) в «queue» (который имеет тип unique_ptr )? –

+2

Буфер также должен быть указателем. Вы можете использовать 'unique_ptr buffer {new Buffer()};', а затем 'queue.push_back (move (buffer));'. – Sorin

+0

@Sorin .. Хм .. после того, как вы переместили unique_ptr, можете ли вы переделать его и сделать еще один новый? –

Смежные вопросы