pthread_join() вызывает ошибку сегментации

Я работаю над пониманием потоков и столкнулся с этой ошибкой сегментации, которую я не могу исправить. Я сузил ошибку до функции pthread_join(), но не могу двигаться дальше. Насколько я понимаю, цикл for должен быть таким же, как цикл для pthread_create(), и что передаваемая переменная представляет собой разыменованный указатель, передаваемый в функцию pthread_exit(). Любое направление будет с благодарностью.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

//void *runner(void *param);

void *pFactor(void *param)
{
        int *pFArray = malloc(sizeof(int) *32);
        int myNum = atoi(param);
        int count = 0;

        printf("I'm getting here");

        while (myNum % 2 == 0)
        {
                pFArray[count] = 2;
                myNum = myNum/2;
                count++;
        }

        for (int i = 3; i < sqrt(myNum); i += 2)
        {
                while (myNum % i == 0)
                {
                        pFArray[count] = i;
                        myNum = myNum/i;
                        count++;
                }
        }

        if (myNum > 2)
        {
                pFArray[count] = myNum;
        }

        //int *arrPtr = (int*) malloc(10);
        //arrPtr = pFArray;
        //return (void *) arrPtr;
        //return fprint("I made it to the end of the pFactor function")
        pthread_exit(pFArray);

}

int main(int argc, char *argv[])
{
        pthread_t tid[argc];
        pthread_attr_t attr;

        if (argc == 0)
        {
                fprintf(stderr, "usage: a.out <integer value>\n");
                return -1;
        }
        if (argc < 0)
        {
                fprintf(stderr, "%d must be >= 0\n", atoi(argv[1]));
                return -1;
        }

        /* Get the default attributes */
        pthread_attr_init(&attr);
        /* Create the thread */
        for (int i = 1; i < argc; i++)
        {
                tid[i] = i;
                pthread_create(&tid[i], &attr, pFactor, &argv[i]);
                printf("still working\n");
        }
        printf("still working\n");
        /* Wait for the thread to exit */
        for (int i = 1; i < argc; i++)
        {
                tid[i] = i;
                void *my_Ptr;
                printf("still working 1\n");
                pthread_join(tid[i], &my_Ptr);
                printf("still working 2\n");
                for (;;)
                {
                        printf("%d", atoi(argv[i]));
                        printf(": %d",((int*) my_Ptr)[i-1]);
                }
                //printf("%d", atoi(argv[i]));
                //printf(": %d",((int*) my_Ptr)[i-1]);
        } /*This is where you want to pass in the sum variable*/
}

person Patrick Kesler    schedule 27.02.2019    source источник
comment
Почему вы назначаете tid[i]? В любой петле? pthread_create() заполняет соответствующее значение, и это значения, которые вы должны позже передать pthread_join().   -  person John Bollinger    schedule 28.02.2019


Ответы (2)


Запуск вашей программы под valgrind подтверждает ваш диагноз, что проблема возникает при вызове pthread_join. Это также можно определить, запустив его в отладчике, но Valgrind часто особенно полезен при ошибках сегментации, поскольку его анализ использования памяти также часто помогает определить причину проблемы.

Однако в этом случае основная проблема ясна: вы вызываете pthread_join() с недопустимым первым аргументом. Вы, кажется, немного не поняли:

Насколько я понимаю, цикл for должен быть таким же, как цикл для pthread_create()

Нет, не обязательно. Единственная существенная ассоциация с pthread_create заключается в том, что первый аргумент, идентификатор потока, должен быть значением, которое было сохранено pthread_create(), идентифицируя поток, который не был ни отсоединен, ни уже присоединен. Возможно, уместно выполнять соединения в цикле, аналогично тому, в котором вы запускаете потоки, но это зависит от конкретных требований вашего приложения. Однако, как правило, эти требования включают в себя выполнение всех рабочих потоков до того, как основной поток пройдет какую-то точку, и для этого каждый из них должен быть объединен.

и что передаваемая переменная является разыменованным указателем, передаваемым в функцию pthread_exit().

Зная, как ведет себя pthread_join(), я могу сжать эти слова в подходящую форму. Лично я бы сказал что-то вроде: «Второй аргумент, если он не нулевой, является указателем на место, в которое нужно записать возвращаемое значение функции потока или значение, переданное в pthread_exit()».

В любом случае, основная проблема заключается в том, что я уже выразил в комментариях: в вашем цикле соединения вы перезаписываете идентификаторы потоков, предоставленные pthread_create, и передаете свои произвольные значения pthread_join. Они не идентифицируют ваши потоки, и в случае, если ваша реализация pthreads аналогична моей, неверные идентификаторы потоков фактически являются недействительными указателями. Что вы, кажется, не понимаете, так это то, что именно pthread_create генерирует и назначает идентификаторы потоков. Вот почему вы должны передать ему адрес для хранения идентификатора. Как следствие, бесполезно инициализировать переменную идентификатора потока перед передачей ее адреса в pthread_create.


Устранение этой проблемы и повторный запуск вашей программы под valgrind показывает, что у вас есть дополнительная проблема в вашей функции потока, о чем также упоминается в вашем другом ответе. Это происходит отчасти из-за того, что ваш четвертый аргумент pthread_create не соответствует тому, как ваша функция потока использует свой аргумент.

Четвертый аргумент pthread_create передается прямо в функцию потока. Вы проходите мимо &argv[i], который является адресом char *, он же char **, автоматически преобразованным в void *. Ваша функция потока передает свой аргумент непосредственно в atoi() с автоматическим преобразованием в тип char *. Обратите внимание, что char * != char **. Я думаю, вы хотите, чтобы четвертый аргумент pthread_create был просто argv[i]. По крайней мере, у этого есть тип, соответствующий вашему использованию.


Сделав это исправление, я обнаружил, что ваша программа заканчивается бесконечным циклом внутри вашего цикла pthread_join. Я не уверен, почему вы там зацикливаетесь - это кажется совершенно бесполезным.

person John Bollinger    schedule 27.02.2019

В вашем коде есть ошибка записи за пределы. Проверка вашего кода в реальном времени

Ниже приведено сообщение об ошибке.

== Начало сообщения Stensal DTS == скопируйте начало здесь ==(56.127)==

Ошибка выполнения: [запись за пределами границ]
Продолжение выполнения может привести к неопределенному поведению, прервать!

-
- Writing 4 bytes to 0x8fa0090 will corrupt the adjacent data.
- 
- The object to-be-written (start:0x8fa0010, size:128 bytes) is allocated at
-     file:/prog.c::10, 24
- 
-  0x8fa0010               0x8fa008f
-  +------------------------+
-  |the object to-be-written|......
-  +------------------------+
-                            ^~~~~~~~~~
-        the write starts at 0x8fa0090 that is right after the object end.
- 
- Stack trace (most recent call first) of the write.
- [1]  file:/prog.c::18, 17
- [2]  file:/musl-1.1.10/src/thread/pthread_create.c::168, 17
-

=== Конец сообщения Stensal DTS ==== скопируйте сюда конец ============

person stensal    schedule 27.02.2019