#c #multithreading
#c #многопоточность
Вопрос:
Я написал очень простой код для использования потока C 11. Я обнаружил, что если я использую указатель структуры в качестве аргумента для потоковой функции, значение внутри структуры не может быть передано правильно. Пожалуйста, скажите мне, где я ошибся. Спасибо.
#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
typedef struct {
int tid;
int bbb;
} arguments;
void blahblah (void * args) {
int tid1 = ((arguments*)args)->tid;
int b = ((arguments*)args)->bbb;
printf("the tid is %d, %dn", tid1, b);
}
int main () {
int n = 5;
// thread * ThreadArray = (thread*)malloc(n * sizeof(thread));
thread ThreadArray[n];
int tid = 0, bbb = 6;
for (int i = 0; i < n; i ) {
arguments args = {tid, bbb};
tid ;
bbb--;
printf("the data inside %d, %dn", args.tid, args.bbb);
ThreadArray[i] = thread (blahblah, amp;args);
}
for (int i = 0; i < n; i ) {
ThreadArray[i].join ();
}
return 1;
}
Результат выглядит так:
the data inside 0, 6
the data inside 1, 5
the data inside 2, 4
the data inside 3, 3
the tid is 3, 3
the tid is 3, 3
the tid is 4, 2
the data inside 4, 2
the tid is 4, 2
the tid is 4, 2
Комментарии:
1. Вы не передаете структуру в качестве аргумента, вы передаете указатель в качестве аргумента.
2. ДА. Я пытаюсь передать указатель, который указывает на структуру.
Ответ №1:
Вы передаете адрес временного arguments
экземпляра, поэтому у вас нет гарантий, что он действителен, когда ваш поток пытается его использовать. Вместо этого передайте args
напрямую, поскольку библиотека потоков C поддерживает аргументы по значению.
void blahblah (arguments args)
{
printf("the tid is %d, %dn", args.tid, args.bbb);
}
// ...
for (int i = 0; i < n; i )
{
arguments args = {tid, bbb};
tid ;
bbb--;
printf("the data inside %d, %dn", args.tid, args.bbb);
ThreadArray[i] = thread (blahblah, args);
}
Комментарии:
1. Спасибо за ответ. Если мне действительно нужно передать указатель структуры в некоторых случаях, что мне делать? Потому что структуре иногда нужно удерживать выходное сообщение для потоковой функции.
2. Вам необходимо убедиться, что точка остается действительной столько, сколько необходимо. В идеале вы должны использовать интеллектуальный указатель (unique_ptr или shared_ptr), поскольку они обрабатывают время жизни для вас.
3. @YueWang Вы можете использовать a
std::shared_ptr
для такого случая.4. @YueWang экземпляр
arguments
инструкции created byarguments args = {tid, bbb};
перестает существовать после того, как выполнение достигает наименее вложенной заключающей фигурной скобки } . Новый может быть создан или не создан в том же месте на следующей итерации. Вы должны убедиться, что срок службы объекта не меньше срока службы потока, пока он использует этот объект
Ответ №2:
Внутри вашего цикла вы передаете указатель на локальную arguments
переменную, которая выходит за пределы области видимости сразу после завершения std::thread
работы конструктора, поэтому к моменту blahblah()
попытки доступа к ней память, вероятно, будет недействительной.
Вам нужно будет объявить arguments
память вне цикла, чтобы она оставалась достаточно долго blahblah()
для ее использования, например:
#include <thread>
#include <cstdio>
using namespace std;
struct arguments {
int tid;
int bbb;
};
void blahblah (arguments * args) {
int tid1 = args->tid;
int b = args->bbb;
printf("the tid is %d, %dn", tid1, b);
}
int main() {
const int n = 5;
thread ThreadArray[n];
arguments args[n];
int tid = 0, bbb = 6;
for (int i = 0; i < n; i ) {
args[i].tid = tid ;
args[i].bbb = bbb--;
printf("the data inside %d, %dn", args[i].tid, args[i].bbb);
ThreadArray[i] = thread(blahblah, amp;args[i]);
}
for (auto amp;t : ThreadArray) {
t.join();
}
return 1;
}
Альтернативно:
#include <thread>
#include <memory>
#include <cstdio>
using namespace std;
struct arguments {
int tid;
int bbb;
};
void blahblah (unique_ptr<arguments> amp;args) {
int tid1 = args->tid;
int b = args->bbb;
printf("the tid is %d, %dn", tid1, b);
}
int main() {
const int n = 5;
thread ThreadArray[n];
int tid = 0, bbb = 6;
for (int i = 0; i < n; i ) {
auto args = make_unique<arguments>();
args->tid = tid ;
args->bbb = bbb--;
printf("the data inside %d, %dn", args->tid, args->bbb);
ThreadArray[i] = thread(blahblah, move(args));
}
for (auto amp;t : ThreadArray) {
t.join();
}
return 1;
}
Или вместо этого вы можете передать arguments
значение by:
#include <thread>
#include <cstdio>
using namespace std;
struct arguments {
int tid;
int bbb;
};
void blahblah (arguments args) {
int tid1 = args.tid;
int b = args.bbb;
printf("the tid is %d, %dn", tid1, b);
}
int main() {
const int n = 5;
thread ThreadArray[n];
int tid = 0, bbb = 6;
for (int i = 0; i < n; i ) {
arguments args{tid , bbb--};
printf("the data inside %d, %dn", args.tid, args.bbb);
ThreadArray[i] = thread(blahblah, args);
}
for (auto amp;t : ThreadArray) {
t.join();
}
return 1;
}
Или вы можете просто arguments
полностью избавиться, поскольку std::thread
поддерживает функции с несколькими параметрами:
#include <thread>
#include <cstdio>
using namespace std;
void blahblah (int tid, int bbb) {
printf("the tid is %d, %dn", tid, bbb);
}
int main() {
const int n = 5;
thread ThreadArray[n];
int tid = 0, bbb = 6;
for (int i = 0; i < n; i ) {
printf("the data inside %d, %dn", tid, bbb);
ThreadArray[i] = thread(blahblah, tid , bbb--);
}
for (auto amp;t : ThreadArray) {
t.join();
}
return 1;
}