Как синхронизировать потоки? - PullRequest
4 голосов
/ 08 мая 2011

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

printf("\ti'm %dth thread:)", j);  
printf("\t%c  %d  %d  %d \n", arr[j].op, arr[j].byte, seq, no_file);

Кроме того, даже некоторые темы печатают эту строку дважды. что случилось с этим процессом? А как реорганизовать этот код, чтобы потоки печатали строку ровно один раз?

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>

typedef struct {char op; int byte; int seq; int no_file; } ARRAY; 

ARRAY *arr;

void *thread_operation(void *arg){
    int j =*((int*)arg);
    seq = arr[j].seq;
    int no_file = arr[j].no_file;
    printf("\ti'm %dth thread:)", j);
    printf("\t%c  %d  %d  %d \n", arr[j].op, arr[j].byte, seq, no_file);
}

int main()
{
    int err, j, i = 10;
    long int tid;
    arr = (ARRAY*)malloc(sizeof(ARRAY) * i);
    srand(time(NULL));
    for (i = 0; i <= 10; i++){
        arr[i].op = 'r';
        arr[i].byte = (rand() % 10);
        arr[i].seq = i;
        arr[i].no_file = i + 10;
}

    for(j = 0; j < 10; j++){
        printf("creating %dth thread.....", j);
        err = pthread_create(&tid, NULL, thread_operation, &j);
        if(err != 0)
        printf("%s\n", strerror(err));
        printf("%dth done\n", j);
    }

    return 0;
}

Это результат моего компьютера

creating 0th thread.....0th done
creating 1th thread.....    i'm 0th thread:)    r  9  0  10
1th done
creating 2th thread.....    i'm 2th thread:)    r  3  2  12
    i'm 2th thread:)    r  3  2  12
2th done
creating 3th thread.....    i'm 3th thread:)    r  6  3  13
3th done
creating 4th thread.....    i'm 4th thread:)    r  9  4  14
4th done
creating 5th thread.....    i'm 5th thread:)    r  3  5  15
5th done
creating 6th thread.....    i'm 6th thread:)    r  2  6  16
6th done
creating 7th thread.....    i'm 7th thread:)    r  2  7  17
7th done
creating 8th thread.....8th done
creating 9th thread.....    i'm 8th thread:)    r  6  8  18
9th done
    i'm 9th thread:)    r  8  9  19  
    i'm 9th thread:)    r  8  9  19

Ответы [ 3 ]

6 голосов
/ 08 мая 2011

Вам нужно использовать мьютексы, чтобы избежать условий гонки, а также использовать pthread_join для синхронизации всех ваших потоков до того, как процесс завершится.

Мьютексы позволяют вам останавливать некоторые потоки, пока один из них выполняетдействие с использованием общего ресурса (см. man pthread_mutex_lock, pthread_mutex_init)

pthread_join имеет важное значение в вашем коде, потому что он заставляет ваш основной поток ждать других потоков, которые вы создали, если вы не используете его, вы 'не уверен, что все потоки будут завершены, когда основной поток вернется из основного.

2 голосов
/ 08 мая 2011

Причина, по которой некоторые печатают дважды (например, номер потока 9), заключается в том, что вы передаете указатель на переменную цикла в качестве входных данных для thread_operation.

for(j = 0; j < 10; j++){
    err = pthread_create(&tid, NULL, thread_operation, &j);<---here

что & j в конечном итоге разыменовывается thread_operation:

void *thread_operation(void *arg){
    int j =*((int*)arg);<---here

но в этот момент цикл может продвинуться, и значение j (в операции потока) будет таким, каким j окажется в цикле прямо сейчас. Способ исправить это - передать не указатель, а значение j в конструктор потока. Измените ваш pthread_create, чтобы передать значение:

pthread_create(&tid, NULL, thread_operation, (void*) j);

и в вашем потоке приведите значение из аргумента потока:

int j =(int)arg;

Теперь технически это зависит от того факта, что int и void* имеют одинаковый размер, тогда как в общем случае это не так. Но это будет работать до тех пор, пока вы не используете гигантские значения int.

для всех остальных проблем @Intrepidd прав в использовании pthread_join, чтобы убедиться, что процесс не завершится до завершения всех ваших потоков.

1 голос
/ 08 мая 2011

Использование printf с неполными строками между потоками обычно не работает.Вы можете получить вывод полностью искаженным.Также порядок, в котором строки появляются на вашем экране, в общем случае будет не порядком выполнения, а порядком, которым потоки обращаются к общему ресурсу stdout.

...