【问题标题】:C passing array to pthread in Dining PhilosopherC 在 Dining Philosopher 中将数组传递给 pthread
【发布时间】:2017-05-09 20:36:16
【问题描述】:

我正在为来自用户输入的 N 位哲学家的餐饮哲学家线程问题编写代码。取消引用 void * 指针时出现错误。我在传递数组时具体做错了什么?

 void *philosopher(void *arg_l);

 int main()
 {   
     int i,A,B;
     scanf("%10d", &A);
     scanf("%10d", &B);
     printf("You got %d phils and %d turns each\n",A,B);

     int args[2];
     args[0] = A;
     args[1] = B;

     pthread_t thread_id[A];
     sem_init(&mutex,0,1);
     for(i=0;i<A;i++)
         sem_init(&S[i],0,0);
     for(i=0;i<A;i++)
     {
         args[2] = phil_num[i];
         pthread_create(&thread_id[i],NULL,philosopher,&args);
         printf("Philosopher %d is thinking\n",i+1);
     }
     for(i=0;i<A;i++)
         pthread_join(thread_id[i],NULL);
}

void *philosopher(void *arg_l)
{
    arg_l[0] = int A;
    arg_l[1] = int B;
    ...
    return NULL;
}

【问题讨论】:

  • 您需要将arg_l 转换回原始类型,然后才能取消引用它。不然怎么知道arg_l[0]是什么类型?
  • int A 不是分配中的有效语法。
  • 你会如何建议这样做?
  • 在@dbush 发布的答案中
  • 注意:args[2] = phil_num[i]; 超出范围。您必须向每个哲学家传递一个单独的数组,因为不能保证给定线程会在主线程重新分配新值之前读取信息。通常,您将使用结构而不是数组来传递给单个线程的数据;你有一个这些结构的初始化数组,以便每个线程都有自己独特的控制信息。我认为布什先生的回答没有涵盖这一点。

标签: c arrays pthreads


【解决方案1】:

由于arg_l 具有void * 类型,因此不能在其上使用下标运算符[]。这意味着每个元素都有类型void,它不能被实例化。此外,赋值右侧的语法无效。

您需要将线程参数转换为int *,然后才能使用它。此外,您需要传入args 而不获取其地址,因为数组在传递给函数时会衰减为指向第一个元素的指针。

pthread_create(&thread_id[i],NULL,philospher,args);

...

void *philospher(void *arg_l)
{
     int *args = arg_l;
     ...

}

【讨论】:

    【解决方案2】:

    您的台词如下:

    arg_l[0] = int A;
    

    完全坏掉了。你会侥幸逃脱:

    int A = ((int *)arg_l)[0];
    

    您不能有效地取消引用 void *,也不能索引它们(部分原因是需要取消引用,部分原因是在标准 C 中——与 GNU C 相对——sizeof(void) 未定义)。如图所示,您需要通过强制转换然后解除引用来转换为适当的类型。

    注意:args[2] = phil_num[i]; 写入越界(您定义了int args[2];,但看起来您需要int args[3];

    您必须为每个哲学家传递一个单独的数组,因为不能保证给定线程在主线程重新分配新值之前已经读取了信息。通常,您将使用结构而不是数组来传递给单个线程的数据;你有一个这些结构的初始化数组,以便每个线程都有自己独特的控制信息。

    有什么方法可以举个例子吗?

    有点像这样。关键是struct Info的数组,每个都单独初始化(使用C99复合字面量),并将数组的不同元素传递给每个线程,以便它获取自己的数据,而不是试图共享数据与其他线程。

    #include <pthread.h>
    #include <semaphore.h>
    #include <stdio.h>
    
    #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    
    struct Info
    {
        int number;
        int turns;
        int diner;
    };
    
    enum { MAX_PHILOSOPHERS = 10 };
    enum { MAX_TURNS = 99 };
    static sem_t mutex;
    static sem_t S[MAX_PHILOSOPHERS];
    static void *philosopher(void *arg_l);
    
    int main(void)
    {
        int A, B;
        printf("How many philosophers? How many turns? ");
        fflush(stdout);
        if (scanf("%d %d", &A, &B) != 2)
        {
            fprintf(stderr, "Failed to read input\n");
            return 1;
        }
        if (A < 2)
            fprintf(stderr, "You specified too few philosophers (%d)\n", A);
        if (A > MAX_PHILOSOPHERS)
            fprintf(stderr, "You specified too many philosophers (%d, but the maximum is %d)\n",
                    A, MAX_PHILOSOPHERS);
        if (B < 1)
            fprintf(stderr, "You specified too few turns (%d)\n", B);
        if (B > MAX_TURNS)
            fprintf(stderr, "You specified too many turns (%d, but the maximum is %d)\n",
                    B, MAX_TURNS);
        if (A < 2 || A > MAX_PHILOSOPHERS || B < 1 || B > MAX_TURNS)
            return 1;
        printf("You have %d philosophers who get %d turns each\n", A, B);
    
        /* This assignment could be in the thread creation loop before pthread_create() */
        /* Or in the loop that uses sem_init() */
        struct Info info[A];
        for (int i = 0; i < A; i++)
            info[i] = (struct Info){ A, B, i};
    
        sem_init(&mutex, 0, 1);
        for (int i = 0; i < A; i++)
            sem_init(&S[i], 0, 0);
    
        pthread_t thread_id[A];
        for (int i = 0; i < A; i++)
        {
            pthread_create(&thread_id[i], NULL, philosopher, &info[i]);
            printf("Philosopher %d is thinking\n", i + 1);
        }
    
        for (int i = 0; i < A; i++)
            pthread_join(thread_id[i], NULL);
    
        printf("Dinner is over\n");
        return 0;
    }
    
    static void *philosopher(void *arg_l)
    {
        struct Info *info = arg_l;
        printf("N = %d, T = %d, I = %d\n", info->number, info->turns, info->diner);
        /* ...do dining stuff; remember to share nicely!... */
        return 0;
    }
    

    #pragma 允许代码在 macOS Sierra 上编译,它没有 &lt;semaphore.h&gt; 函数的工作版本——它们只是返回错误指示并将 errno 设置为 ENOSYS(函数未实现) . 这段代码还应该检查 pthread 函数和信号量操作的返回值——不这样做就是懒惰。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-09
      • 2014-12-24
      • 2011-12-11
      • 2021-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-10
      相关资源
      最近更新 更多