【问题标题】:Dynamically allocating threads in C在 C 中动态分配线程
【发布时间】:2014-06-15 10:47:43
【问题描述】:

我正在用 C 创建一个小程序,它计算用户输入的数字的能力,直到用户输入一个负数。它使用线程来做到这一点。

我在运行时遇到分段错误,所以我做错了什么,但我不知道具体是什么。

这是我的代码:

/* 
 * File:   main.c
 * Author: thomasvanhelden
 *
 * Created on June 15, 2014, 3:17 AM
 */

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

/**
 * Calculates faculty of given number
 *      Can run as a thread
 * @param param The given number
 * @return Doesn't return anything
 */
void *fac(void *param) {
    int* number = (int*) param;
    int faculty = 1;
    int i; // counter

    printf("De faculteit van %i is: ", number);

    for (i = 2; i <= number; i++) {
        faculty *= i;
    }

    printf("%i\n", faculty);
}

/*
 * 
 */
int main(int argc, char** argv) {
    pthread_t **threads; 
    int getal, numThreads = 0, counter, stop = 0;

    // ask for numbers until user enters negative number
    while (stop == 0) {
        scanf("%i", getal);

        if (getal >= 0) {
            numThreads++;
            threads = realloc(threads, sizeof(pthread_t*) * (numThreads+1));
            threads[numThreads - 1] = malloc(sizeof(pthread_t));

            // Create the thread
            if (pthread_create(&threads[numThreads - 1], NULL, fac, &getal)) {
                // something went wrong
                printf("Error creating thread %i!\n", numThreads);
                return 1;
            }

        } else {
            // User entered negative number and wants to stop
            stop = 1;
        }
    }

    // join all the threads
    for (counter = 0; counter < numThreads; counter++) {
        if (pthread_join(threads[counter], NULL)) {
            printf("Something went wrong joining thread %i\n", counter + 1);
        }
    }


    return (EXIT_SUCCESS);
}

【问题讨论】:

    标签: c multithreading dynamic pthreads


    【解决方案1】:

    我认为您的意思是“阶乘”?无论如何,您的代码存在多个问题。即使没有启用严格标志,我也会收到以下警告:

    fac.c:23:40: warning: format specifies type 'int' but the argument has type 'int *' [-Wformat]
        printf("De faculteit van %i is: ", number);
                                 ~~        ^~~~~~
    fac.c:25:19: warning: ordered comparison between pointer and integer ('int' and 'int *')
        for (i = 2; i <= number; i++) {
                    ~ ^  ~~~~~~
    fac.c:30:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^
    fac.c:41:21: warning: format specifies type 'int *' but the argument has type 'int' [-Wformat]
            scanf("%i", getal);
                   ~~   ^~~~~
    fac.c:49:32: warning: incompatible pointer types passing 'pthread_t **' (aka 'struct _opaque_pthread_t ***') to
          parameter of type 'pthread_t *' (aka 'struct _opaque_pthread_t **'); remove &
          [-Wincompatible-pointer-types]
                if (pthread_create(&threads[numThreads - 1], NULL, fac, &getal)) {
                                   ^~~~~~~~~~~~~~~~~~~~~~~~
    /usr/include/pthread.h:310:42: note: passing argument to parameter here
    int pthread_create(pthread_t * __restrict, const pthread_attr_t * __restrict,
                                             ^
    fac.c:63:26: warning: incompatible pointer types passing 'pthread_t *' (aka 'struct _opaque_pthread_t **') to
          parameter of type 'pthread_t' (aka 'struct _opaque_pthread_t *'); dereference with *
          [-Wincompatible-pointer-types]
            if (pthread_join(threads[counter], NULL)) {
                             ^~~~~~~~~~~~~~~~
                             *
    /usr/include/pthread.h:333:28: note: passing argument to parameter here
    int pthread_join(pthread_t , void **) __DARWIN_ALIAS_C(pthread_join);
                               ^
    6 warnings generated.
    

    事实上,如果你在gdb下运行程序,输入数字后它会崩溃:

    ...
    4
    
    Program received signal EXC_BAD_ACCESS, Could not access memory.
    Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000000
    0x00007fff92c1401a in __svfscanf_l ()
    (gdb) bt
    #0  0x00007fff92c1401a in __svfscanf_l ()
    #1  0x00007fff92c0c0eb in scanf ()
    #2  0x0000000100000d72 in main (argc=1, argv=0x7fff5fbffa18) at fac.c:41
    

    查看带有bt 的堆栈跟踪,我们立即看到它在您调用scanf() 的第41 行崩溃。如果您回头查看编译器警告,它会告诉您它需要一个int*,但您只传递了一个int。这是因为scanf 需要一个指针来修改用户输入的变量。

    如果你修复了所有剩余的警告,你的代码就可以工作。

    • 当你想要它的值时,你需要在 fac 函数中取消对 number 的引用
    • 您需要将threads 初始化为NULL,以便realloc 可以工作(否则它是未定义的,可能是非零,因此缓冲区永远不会被(重新)分配
    • pthread_createpthread_join 调用需要更新,以便值/指针与预期签名匹配

    进行上述更改后,我可以按预期运行它:

    $ ./fac_fixed
    3
    De faculteit van 3 is: 6
    4
    De faculteit van 4 is: 24
    5
    De faculteit van 5 is: 120
    6
    De faculteit van 6 is: 720
    7
    De faculteit van 7 is: 5040
    8
    De faculteit van 8 is: 40320
    9
    De faculteit van 9 is: 362880
    12
    De faculteit van 12 is: 479001600
    -1
    

    至于代码的结构,我不明白你为什么要创建一个线程数组,因为你一次只计算一个,顺序。您实际上最多只需要一个工作线程,但由于main 无论如何都在阻塞连接,所以它实际上并不需要在线程中。但至少它不会崩溃!

    【讨论】:

    • 非常感谢您花时间修复我的代码!是的,不需要创建线程数组。但我把它作为一个练习,所以它没有真正的目的。
    • 是的!再次感谢!
    【解决方案2】:

    当您第一次调用realloc() 时,您应该将threads 设置为NULL。实际上,您正在传递一个未初始化的指针,它是未定义的行为

    1) 初始化为0:

    pthread_t **threads = 0; 
    

    2)您还打印了指针,而不是它们指向的内容:

    printf("De faculteit van %i is: ", *number);
    

    3) scanf() 需要&amp;,因为它期望int * 用于%d

    scanf("%i", &getal);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-05
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 2015-07-14
      • 2021-02-12
      相关资源
      最近更新 更多