pthread_join () вызывает ошибку сегментации - PullRequest
0 голосов
/ 28 февраля 2019

Я работаю над пониманием потоков и столкнулся с этой ошибкой сегментации, которую я не могу исправить.Я сузил ошибку до функции 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*/
}

Ответы [ 2 ]

0 голосов
/ 28 февраля 2019

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

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

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

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

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

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

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


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

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


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

0 голосов
/ 28 февраля 2019

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

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

== Сообщение начала DTS Stensal == начало копирования здесь == (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
-

=== Сообщение DTS об окончании Stensal ==== скопировать конец здесь ============

...