pthread_create пропускает или повторяет - PullRequest
0 голосов
/ 03 мая 2018

Функция pthread_create пропускается или иногда вызывается дважды. Вопрос, который я решаю:

Учитывая глобальный массив, который содержит число от 1 до 100. Вы должны сделать 10 потоков, и каждый поток должен найти сумму квадрата из 10 чисел.

Тема 1 должна рассчитываться от 1 до 10

Тема 2 должна рассчитываться от 11 до 20

... и так далее.

Каждый поток должен возвращать свою индивидуальную сумму в глобальную переменную sum, инициализированную нулем.

Моя попытка:

#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;
}

Я использовал семафоры. Так что только один поток одновременно обращается к глобальному ресурсу.

Вывод, который я получаю:

Экран вывода

Мой вопрос: почему он повторяет некоторые значения и пропускает некоторые? Я не правильно использую 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);

}

1 Ответ

0 голосов
/ 03 мая 2018

Этот код передает один и тот же адрес 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));
...