【问题标题】:pthread_create skips or repeatspthread_create 跳过或重复
【发布时间】:2018-05-03 09:39:25
【问题描述】:

pthread_create 函数被跳过或有时被调用两次。 我要解决的问题是:

给定一个包含从 1 到 100 的数字的全局数组。您需要创建 10 个线程,每个线程必须找到 10 个数字的平方和。

线程 1 必须从 1 计算到 10

线程 2 必须从 11 计算到 20

...等等。

每个线程必须将其单独的总和返回到一个用零初始化的全局变量总和。

我的尝试:

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<stdlib.h>
#include<semaphore.h>

int arr[100];

sem_t s;

int sum=0;

void *calculate(void *i){
    sem_wait(&s);
    int j=(*((int*)i));
    int k;
    printf("j: %d\n",j);
    int temp=0;
    for(k=j*10;k<(j*10)+10;k++){
        temp=temp+(arr[k]*arr[k]);
    }
    sum+=temp;

    printf("sum: %d j: %d\n\n",sum,j);

    sem_post(&s);
    pthread_exit(NULL);
}

int main(){
    sem_init(&s,0,1);
    pthread_t threads_array[10];
    int i=0;
    int *k=(int *)malloc(sizeof(int));
    for(i=0;i<100;i++){
        arr[i]=i+1;
    }

    int temp=0,temp_i;

    for(i=0;i<10;i++){
        (*k)=i;
        printf("k: %d\n",(*k));
        pthread_create(&(threads_array[i]),NULL,calculate,(void*)k);
    }
    for(i=0;i<10;i++){
       pthread_join(threads_array[i],NULL);
    }

    printf("%d",sum);
    return 0;
}

我使用过信号量。这样一次只有一个线程访问全局资源。

我得到的输出是:

Output screen

我的问题是为什么它会重复一些值并跳过一些值?我没有正确使用 pthread_create?

我也尝试过每次都使用新的 k 值:

for(i=0;i<2;i++){
    int *k=&i;
    printf("k: %d\n",(*k));
    pthread_create(&(threads_array[i]),NULL,calculate,(void*)k);

}

【问题讨论】:

  • 与其链接图像,不如将输出粘贴到帖子本身中,就像您对代码所做的那样。
  • k 在你的线程之间共享...使用一些线程本地存储或十个变量的数组...不要拿信号量来计算本地和,只是用它来保护sum+= 部分

标签: c pthreads posix


【解决方案1】:

这段代码将k的相同地址传递给每个线程,但是它改变了那个内存中的值

for(i=0;i<10;i++){
    (*k)=i;
    printf("k: %d\n",(*k));
    pthread_create(&(threads_array[i]),NULL,calculate,(void*)k);
}

这段代码运行时

void *calculate(void *i){
    sem_wait(&s);
    int j=(*((int*)i));
        .
        .
        .

该值可能已更改,因为主线程更改了它。

这会更好,因为它传递了i,但这取决于intptr_t 的存在以及允许转换回int 的特定于平台的行为,所以它不是严格兼容的 C 代码:

for(i=0;i<10;i++){
    pthread_create(&(threads_array[i]),NULL,calculate,(void*)(intptr_t)i);
}

void *calculate(void *i){
    sem_wait(&s);
    int j= (intptr_t)i;

这会将i 作为void * 指针值传递。

但如果存在intptr_t,那就更好了:

intptr_t i;
    .
    .
    .
for(i=0;i<10;i++){
    pthread_create(&(threads_array[i]),NULL,calculate,(void*)i);
}

void *calculate(void *i){
    sem_wait(&s);
    intptr_t j= (intptr_t)i;

实际上,已经没有多少平台可以使用这种方法了。

或者,在严格符合 C 的情况下,要传递实际 int 值的地址,您需要为每个线程运行时保证存在的单独的 int

// this is a local variable, but since it's in the same scope as
// both pthread_create() and pthread_join(), it will still exist
// for the entire lifetime of each thread created
int threadnum[10];

for(i=0;i<10;i++){
    threadnum[i]=i;
    pthread_create(&(threads_array[i]),NULL,calculate,(void*)&(threadnum[i]));
}

void *calculate(void *i){
    sem_wait(&s);
    int j=(*((int*)i));

【讨论】:

  • 我还尝试在每次循环运行时传递新的 k 值。请检查编辑
  • @JasmineKaur 您将相同的地址传递给每个线程。然后您修改该内存中的值,但您无法控制哪个线程首先运行,并且您不知道它们将在 何时 运行。在pthread_join() 循环中阻塞主线程之前,这些线程甚至可能不会启动。您的编辑并没有真正帮助,因为您传递的本地循环变量的地址在线程尝试取消引用指针时可能超出范围。
  • 太棒了。那个数组的想法似乎很合乎逻辑,我明白了我的错误
猜你喜欢
  • 2012-09-29
  • 2021-11-24
  • 1970-01-01
  • 2013-01-07
  • 1970-01-01
  • 1970-01-01
  • 2013-12-05
相关资源
最近更新 更多