Не удается передать значения внутри структуры, когда указатель структуры используется в качестве аргумента потоковой функции правильно?

#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 by arguments 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;
}