简体   繁体   中英

Can not pass values inside a struct, when use the struct pointer as an argument to a thread function correctly?

I wrote a very simply code to use C++11 thread. I found that if I use struct pointer as an argument for the threaded function, the value inside the struct can not be passed correctly. Please tell me where I did wrong. Thanks.

#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, %d\n", 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, %d\n", args.tid, args.bbb);
        ThreadArray[i] = thread (blahblah, &args);
    }

    for (int i = 0; i < n; i++) {
        ThreadArray[i].join ();
    }
    return 1;
}

The result is like:

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

You're passing the address of a temporary arguments instance, so you have no guarantees it's valid when your thread tries to use it. Instead, pass the args directly, since C++'s thread library supports arguments by value.

void blahblah (arguments args)
{
    printf("the tid is %d, %d\n", args.tid, args.bbb);
}

// ...

    for (int i = 0; i < n; i++)
    {
        arguments args = {tid, bbb};
        tid++;
        bbb--;
        printf("the data inside %d, %d\n", args.tid, args.bbb);
        ThreadArray[i] = thread (blahblah, args);
    }

Inside of your loop, you are passing a pointer to a local arguments variable that goes out of scope right after the std::thread constructor exits, so the memory is likely to be invalid by the time blahblah() tries to access it.

You would have to declare the arguments memory outside of the loop so it stays around long enough for blahblah() to use it, eg:

#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, %d\n", 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, %d\n", args[i].tid, args[i].bbb);
        ThreadArray[i] = thread(blahblah, &args[i]);
    }

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

    return 1;
}

Alternatively:

#include <thread>
#include <memory>
#include <cstdio>
using namespace std;

struct arguments {
    int tid;
    int bbb;
};

void blahblah (unique_ptr<arguments> &args) {
    int tid1 = args->tid;
    int b = args->bbb;

    printf("the tid is %d, %d\n", 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, %d\n", args->tid, args->bbb);
        ThreadArray[i] = thread(blahblah, move(args));
    }

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

    return 1;
}

Or, you can pass the arguments by value instead:

#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, %d\n", 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, %d\n", args.tid, args.bbb);
        ThreadArray[i] = thread(blahblah, args);
    }

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

    return 1;
}

Or, you caan simply get rid of arguments altogether, as std::thread supports functions with multiple parameters:

#include <thread>
#include <cstdio>
using namespace std;

void blahblah (int tid, int bbb) {
    printf("the tid is %d, %d\n", 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, %d\n", tid, bbb);
        ThreadArray[i] = thread(blahblah, tid++, bbb--);
    }

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

    return 1;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM