Как передать значение int через параметр-указатель void функции и преобразовать его обратно в значение int? - PullRequest
1 голос
/ 13 мая 2019

Я пытаюсь создать многопоточную программу, которая создает поток для каждого файла, который его берет (file1.txt в file20.txt), и мне нужно передать переменную в функцию, используя pthread_create.У меня возникают трудности при передаче значения int в функцию, потому что pthread_create принимает только void*, поэтому моя функция должна принимать void*.

У меня есть некоторый опыт работы с указателями, но я неочень хорошо понимаю концепцию пустого указателя.Насколько мне удалось выяснить, это то, что мой pthread_create должен выглядеть как-то похожим на этот pthread_create(&tids[i], NULL, getSales, (void*)i );

в main ():

using namespace std;

int main(int argc, char **argv){
    int numfiles = 20;
    // Thread_ID's
    pthread_t tids[numfiles];

    // create threads
    for(int i = 1; i <= numfiles; i++){
        pthread_create(&tids[i], NULL, getSales, (void*)i );
    }

    // wait until threads are done
    //join threads together so they run simultaneously
    for(int i = 1; i <= numfiles; i++){
        pthread_join(tids[i], NULL);
    }
}

в настоящее время в getSales:

void* getSales(void* fileNum){
    int* num = (int*)fileNum;
    cout << &num <<endl;
    pthread_exit(0);
}

в настоящее время, когда я компилирую этот код, он дает сбой и дает мне несколько строк обратной трассировки, но кажется, что ошибка - только функция getSales, в настоящее время выходные данные должны печатать числа от 1 до 20 в случайном порядке.потому что функция многопоточная.

gcc staplemax.cpp -lpthread -o staplemax
staplemax.cpp: In function ‘int main(int, char**)’:
staplemax.cpp:114:57: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
         pthread_create(&tids[i], NULL, getSales, (void*)i );
                                                         ^
/tmp/ccf6zgpk.o: In function `getSales(void*)':
staplemax.cpp:(.text+0x10e): undefined reference to `std::cout'
staplemax.cpp:(.text+0x113): undefined reference to `std::ostream::operator<<(void const*)'
staplemax.cpp:(.text+0x118): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'

edit :

Сейчас я компилирую с g++ staplemax.cpp -lpthread -o staplemax вместо gcc staplemax.cpp -lpthread -o staplemax, как рекомендовано.

Я также изменил main из-за того, что было указано, что &i, вероятно, изменялось при вызове каждого цикла цикла for.мой код в настоящее время выглядит следующим образом

void* getSales(void* fileNum){
    int num = *(int*)fileNum;
    cout << num <<endl;
    pthread_exit(0);
}

int main(int argc, char **argv){
    int numfiles = 20;

    // Thread_ID
    pthread_t tids[numfiles];
    int args[numfiles];

    // create thread
    for(int i = 0; i < numfiles; i++){
        args[i] = i+1;
        pthread_create(&tids[i], NULL, getSales, &args[i] );
    }

   // wait until thread is done  //join
    for(int i = 0; i < numfiles; i++){
        pthread_join(tids[i], NULL);
    }
}

Это компилируется (с g++), но не все цифры 1-20

3
2
9
1
10
6
87

5
4
11
12
13
14
15
16
17
18
19
20

Ответы [ 2 ]

3 голосов
/ 13 мая 2019

Классическое решение для этого состоит в том, чтобы иметь массив объектов, которые представляют аргумент для каждой pthread То есть с каждым потоком будет связано уникальное местоположение, в котором будет храниться его аргумент. Вам просто нужно передать указатель на это уникальное местоположение.

Вот пример:

void *pthread_func(void *_arg) {
    int arg = *(int*)_arg; // we're receiving an int
    // ...
}

int main() {
    pthread_t threads[20];
    int       args[20]; // unique arg location for each thread

    for (int i = 0; i < 20; ++i) {
        args[i] = (whatever you want to pass)

        // create the thread, give it its unique arg location
        pthread_create(&threads[i], NULL, pthread_func, &args[i]);
    }

    // ... join the threads, etc. ...
}

Проблема с передачей переменной цикла по адресу (т. Е. &i) заключается в том, что она может (наиболее точно будет) изменяться до завершения каждого потока.

Например, при итерации i=0 вы передаете &i. Если вы сразу не присоединитесь к вновь созданному потоку, следующая итерация цикла изменит i на 1, что наверняка испортит только что созданный вами поток. Хуже того, возможно, что поток i=0 никогда даже не увидит 0, поскольку создание потока может быть отложено в зависимости от того, что делает система. Поскольку все они указывают на одно и то же место, все они соблюдают одно и то же значение (кроме соображений, касающихся порядка педантичной памяти).

Edit:

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

Единственное предостережение в том, что приведение между целочисленными типами и указателями допускается только в том случае, если они имеют одинаковое количество битов. Чтобы облегчить это, используйте intptr_t или uintptr_t в качестве посредника.

Вот пример этого:

void *pthread_func(void *_arg) {
    int arg = (int)(intptr_t)_arg; // we're receiving an int encoded as void*
    // ...
}

int main() {
    pthread_t threads[20];

    for (int i = 0; i < 20; ++i) {
        void *arg = (void*)(intptr_t)(whatever you want to pass);

        // create the thread, give it its packed argument
        pthread_create(&threads[i], NULL, pthread_func, arg);
    }

    // ... join the threads, etc. ...
}
3 голосов
/ 13 мая 2019

Вы разыгрываете int на void*.Чтобы отменить это, бросьте void* обратно к int.Итак:

int* num = (int*)fileNum;

Должно быть:

int num = (int)fileNum;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...