2014-10-03 2 views
2

У меня есть программа, которая имеет класс A, который я хочу запустить в потоке. На самом деле, это то, что A является рабочим, и у меня будет некоторое количество из них, которые работают, которые я хочу отслеживать. Моя проблема в том, что мой текущий способ сделать это вызывает утечку памяти, когда я проверяю ее с помощью valgrind.Конструктор потоков C++, используя новый (объект), создает утечки памяти

#include <iostream> 
#include <thread> 
#include <vector> 

class A { 
    public: 
     double foobar; 

     A() : foobar(0) { }; 
     A(double newfoo) : foobar(newfoo) { }; 
     void runA(double asap) { 
      foobar = asap; 
      std::cout << "foobar is now index: " << foobar << std::endl; 
     } 
}; 

int main() { 
    std::vector<std::thread> aThreads; 
    for(int i = 0; i < 10; i++) { 
     aThreads.push_back(std::thread(&A::runA, new A(1), i)); 
    } 

    for(auto& t : aThreads) { 
     t.join(); 
    } 

    return 0; 
} 

Так что я знаю, что эта проблема является new A(100) вызов, и я действительно не знаю, как справиться с этим. Моя фактическая программа намного больше, и поэтому утечка намного больше памяти, поэтому мне интересно, что я могу здесь сделать. Я попытался создать объект в цикле for, а затем с помощью std::move() попытаться передать указанный объект в поток, но это тоже не получилось. Я знаю, что мне нужно передать адрес памяти, и я знаю, что я хочу, чтобы отдельные объекты были разделены, поскольку они будут выполнять разные задачи.

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

+1

Необходимо ли очищать каждый объект, как только закончится связанный поток, или все в порядке, чтобы очистить все после того, как все потоки выполнены? –

+0

Один из вариантов - в конце 'A :: runA()', do 'delete this;'. Но только если 'A' всегда динамически распределяется ..., которую вы можете обеспечить, сделав деструктор закрытым. –

+0

Его не нужно очищать, как только оно выделено, поэтому я расскажу об ответах ниже. Я уже убрал одну из проблем, но я просачиваюсь в косвенную память где-то еще в самих потоках. Я думаю, что valgrind сообщает о том, что сама программа использовалась, поэтому мне нужно проверить это и почему это помечено как плохое. – NuclearAlchemist

ответ

3

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

+0

Это решило некоторые проблемы, и должно было быть очевидно для меня. Теперь valgrind просто говорит мне, что я пропуская связку косвенно, или я не срываю должным образом в конце (что лучше) с участием всех потоков или контейнеров, которые я использую, что также возможно. – NuclearAlchemist

+0

На самом деле это оказалось намного сложнее. Я сделал удаление в потоках, но я все еще терял данные в контейнерах std :: map в каждом потоке. Я понял, что мне нужно уметь отслеживать их из основного потока, просто проезжая указатели, что позволило мне удалить их в конце. Нет утечек памяти! – NuclearAlchemist

4

Сделайте A вызываемым напрямую, затем передайте его по значению.

#include <iostream> 
#include <thread> 
#include <vector> 

class A { 
    public: 
     double foobar; 

     A() : foobar(0) { }; 
     A(double newfoo) : foobar(newfoo) { }; 
     void operator()(double asap) { 
      foobar = asap; 
      std::cout << "foobar is now index: " << foobar << std::endl; 
     } 
}; 

int main() { 
    std::vector<std::thread> aThreads; 
    for(int i = 0; i < 10; i++) { 
     aThreads.push_back(std::thread(A(1), i)); 
    } 

    for(auto& t : aThreads) { 
     t.join(); 
    } 

    return 0; 
} 
+0

В моей второй реализации я собираюсь с этим, пытаясь оптимизировать некоторые вещи в очереди. – NuclearAlchemist