pthread_join()导致分段错误

时间:2019-02-27 21:44:23

标签: c segmentation-fault pthreads coredump 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*/
}

2 个答案:

答案 0 :(得分:1)

valgrind下运行程序可确认您诊断为在调用pthread_join时出现问题。也可以通过在调试器中运行它来确定,但是Valgrind通常对于段错误特别有用,因为它的内存使用分析通常也可以帮助确定问题的原因。

但是,在这种情况下,主要问题很明显:您使用无效的第一个参数调用pthread_join()。您似乎有点误会:

  

我的理解是for循环必须与一个相同   pthread_create()

不,不一定。与pthread_create的唯一重要关联是,第一个参数(线程ID)必须是pthread_create()存储的值,用于标识既未分离也未加入的线程。在与启动线程的循环类似的循环中执行连接可能是适当的,但这取决于应用程序的特定要求。但是,通常,这些要求包括所有工作线程在主线程经过某个点之前完成,并且要实现这一点,必须将每个工作线程都加入。

  

,传入的变量是   被取消引用的指针传递到pthread_exit()   功能。

当我知道pthread_join()的行为时,我可以将这些单词压缩为合适的形状。我自己会说得更像是:“第二个参数,如果非null,则是指向写入线程函数的返回值或传递给pthread_exit()的值的位置的指针。”

无论如何,主要问题是我已经在注释中表达了什么:在您的连接循环中,您将覆盖pthread_create提供的线程ID,并将您的任意值传递给pthread_join这些不能识别您的线程,并且如果您的pthreads实现类似于我的线程,那么错误的线程ID实际上最终是无效的指针。您似乎不欣赏的是pthread_create会生成并分配线程ID。这就是为什么您必须向其传递用于存储ID的地址的原因。因此,在将线程ID变量的地址传递给pthread_create之前初始化线程ID变量是没有用的。


清理该问题并在valgrind下运行程序,再次表明您的线程函数中还有其他问题,如其他答案中所述。之所以发生这种情况,部分原因是您对pthread_create的第四个参数与线程函数对其参数的用法不匹配。

pthread_create的第四个参数直接传递给线程函数。您正在传递&argv[i],这是char *(又称char **)的地址,该地址会自动转换为void *。您的线程函数将其参数直接传递给atoi(),并自动转换为类型char *。请注意char *!= char **。我认为您希望pthread_create的第四个参数只是argv[i]。至少它的类型符合您的用途。


也做了那个更正,我发现您的程序最终在pthread_join循环内的无限循环中结束。我不确定为什么要在那儿循环-它似乎完全是免费的。

答案 1 :(得分:0)

您的代码有一个越界写错误。 A live test of your code

以下是错误消息。

==扩展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
-

===扩展DTS消息的结尾====在此处复制结尾============