2013-11-01 3 views
2

Я немного экспериментирую с std :: thread и C++ 11, и я встречаю странное поведение. Пожалуйста, посмотрите на следующий код:C++ 11 std :: thread странное поведение

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

void thread_sum_up(const size_t n, size_t& count) { 
    size_t i; 
    for (i = 0; i < n; ++i); 
    count = i; 
} 

class A { 
public: 
    A(const size_t x) : x_(x) {} 

    size_t sum_up(const size_t num_threads) const { 
    size_t i; 
    std::vector<std::thread> threads; 
    std::vector<size_t> data_vector; 
    for (i = 0; i < num_threads; ++i) { 
     data_vector.push_back(0); 
     threads.push_back(std::thread(thread_sum_up, x_, std::ref(data_vector[i]))); 
    } 

    std::cout << "Threads started ...\n"; 

    for (i = 0; i < num_threads; ++i) 
     threads[i].join(); 

    size_t sum = 0; 
    for (i = 0; i < num_threads; ++i) 
     sum += data_vector[i]; 
    return sum; 
    } 

private: 
    const size_t x_; 
}; 

int main(int argc, char* argv[]) { 
    const size_t x = atoi(argv[1]); 
    const size_t num_threads = atoi(argv[2]); 
    A a(x); 
    std::cout << a.sum_up(num_threads) << std::endl; 
    return 0; 
} 

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

Просто уточнить: Это только для целей тестирования, чтобы понять, как работает C++.

Однако при компиляции этого кода с помощью команды

g++ -o threads threads.cpp -pthread -O0 -std=c++0x 

на поле Ubuntu, я получаю очень странное поведение, когда я исполняю в результате двоичного. Например:

$ ./threads 1000 4 
Threads started ... 
Segmentation fault (core dumped) 

(должен дать выход: 4000)

$ ./threads 100000 4 
Threads started ... 
200000 

(должен дать выход: 400000)

Кто-нибудь имеет представление о том, что здесь происходит?

Спасибо заранее!

ответ

2

Ваш код имеет много проблем (см даже thread_sum_up примерно 2-3 ошибки), но главная ошибка я нашел поглядывая код здесь:

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

Это приведет к сбою.

Для легкого исправления - добавьте data_vector.reserve(num_threads); сразу после его создания.

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

void thread_sum_up(const size_t n, size_t& count) { 
    size_t i; 
    for (i = 0; i < n; ++i); // see that last ';' there? means this loop is empty. it shouldn't be there 
    count = i; // You're just setting count to be i. why do that in a loop? Did you mean +=? 
} 
+1

Большое спасибо за ваш ответ, ваше предложение исправили проблему. Но не могли бы вы также рассказать, какие другие ошибки в thread_sum_up (просто чтобы сообщить мне, что я делаю неправильно)? –

+0

Я бы наверняка был заинтересован в 2-3 ошибках в 'thread_sum_up'. Если вы каким-то образом не интерпретируете тот факт, что любой оптимизатор превратит его в 'count = n;' как ошибку. – Angew

+0

@SvenHager отредактировал сообщение с ошибками 'thread_sum_up', которые я нашел – rabensky

1

Причиной вашего сбоя может быть то, что std :: ref (data_vector [i]) недействителен следующим push_back в data_vector. Поскольку вы знаете количество потоков, сделайте data_vector.reserve (num_threads), прежде чем начинать отбрасывать потоки, чтобы ссылки не были признаны недействительными.

1

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

Ваши варианты предопределяют необходимый вам размер (vector::reserve - это один из вариантов) или выберите другой контейнер.

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