Я закодировал небольшую программу на C++, чтобы попытаться понять, как многопоточность работает с использованием std::thread
. Вот шаг выполнения моей программы:Многопоточность работает неправильно, используя std :: thread (C++ 11)
- Инициализация матрицы 5x5 целых чисел с уникальным значением «42», содержащимся в классе «Toto» (инициализируется в основном).
- Я печатаю инициализированную матрицу 5x5.
- Заявление
std::vector
из 5 нитей. - Я приложил все темы соответственно своей задаче (
threadTask
method). Каждый поток будет обрабатывать экземплярstd::vector<int>
. - Я присоединяюсь к всем темам.
- Я печатаю новое состояние моей матрицы 5x5.
Вот результат:
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
Оно должно быть:
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
0 0 0 0 0
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
Вот пример кода:
#include <iostream>
#include <vector>
#include <thread>
class Toto
{
public:
/*
** Initialize a 5x5 matrix with the 42 value.
*/
void initData(void)
{
for (int y = 0; y < 5; y++) {
std::vector<int> vec;
for (int x = 0; x < 5; x++) {
vec.push_back(42);
}
this->m_data.push_back(vec);
}
}
/*
** Display the whole matrix.
*/
void printData(void) const
{
for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
printf("%d ", this->m_data[y][x]);
}
printf("\n");
}
printf("\n");
}
/*
** Function attached to the thread (thread task).
** Replace the original '42' value by the another one.
*/
void threadTask(std::vector<int> &list, int value)
{
for (int x = 0; x < 5; x++) {
list[x] = value;
}
}
/*
** Return a sub vector reference according to the range.
*/
std::vector<int> &getDataByRange(int range)
{
return (this->m_data[range]);
}
private:
std::vector<std::vector<int> > m_data;
};
int main(void)
{
Toto toto;
toto.initData();
toto.printData(); //Display the original 5x5 matrix (first display).
std::vector<std::thread> threadList(5); //Initialization of vector of 5 threads.
for (int i = 0; i < 5; i++) { //Threads initializationss
std::vector<int> &vec = toto.getDataByRange(i); //Get each sub-vectors reference.
threadList.at(i) = std::thread(&Toto::threadTask, toto, vec, i); //Each thread will be attached to a specific vector.
}
for (int j = 0; j < 5; j++) {
threadList.at(j).join();
}
toto.printData(); //Second display.
getchar();
return (0);
}
Однако в методе threadTask
, если я печатаю переменная list[x]
, выход c дый правильный. Я думаю, что я не могу напечатать правильные данные в основном, потому что вызов printData() находится в основном потоке, и отображение в функции threadTask
правильное, потому что метод выполняется в своем потоке (а не в основном). Странно, это означает, что все потоки, созданные в родительских процессах, не могут изменить данные в этих родительских процессах? Я думаю, что что-то забыл в своем коде. Я действительно потерян. Кто-нибудь может мне помочь, пожалуйста? Большое спасибо за вашу помощь.
Вам нужно узнать о значении C++ и эталонной семантике. 'std :: vector vec = toto.getData() [i];' создает копию вектора, поэтому оригинал никогда не изменяется. Затем эта копия также копируется в объект потока, и снова никогда не влияет на оригинал. –
Я обновил свой вопрос, используя новую функцию getDataByRange, которая возвращает ссылку на определенный суб-вектор в соответствии с диапазоном.Поэтому я не верну копию, но ссылку. Результат такой же, как после моей модификации. – user1364743
Проблема не в функции getData, это было с std :: vector vec = ... part. Это вызывает конструктор экземпляров vecs, а vec будет другим объектом, чем тот, который возвращается getData. В качестве примечания стороны. Рассмотрим инициализацию вашего вектора в конструкторе классов с помощью конструкторов векторов. Toto(): m_data (5, std :: vector (5, 42)) { } является, по-моему, намного более чистой реализацией. –