Как использовать pthreads для выполнения одновременных операций над массивом с ограничением? - PullRequest
0 голосов
/ 03 мая 2018

Я использую pthreads в C, чтобы выполнить две операции над массивом int: одна операция удваивает значение ячейки, другая - вдвое уменьшает значение ячейки. Если после удвоения ячейки ее значение станет больше максимально допустимого значения, поток должен ждать, пока другой поток не уменьшит значение этой ячейки вдвое. Способ, которым я инициализировал массив, состоит в том, что первые 5 ячеек имеют значение, очень близкое к максимально допустимому, а остальные пять имеют значение, далекое от максимального.

Я решил использовать глобальный мьютекс и условную переменную для этого. В main сначала появляются 10 удвоенных потоков, затем еще 10 потоков в половину. Но тогда моя программа зависает. Я не могу понять, в чем проблема, любая помощь приветствуется.

Моя мотивация состоит в том, чтобы лучше понимать pthreads и условные переменные.

Это код:

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

#define MAX 20
#define THREADS_NUM 10
#define OFFSET 10

typedef struct myStruct {
    int cellId;
} myStruct;

int * cells;

pthread_mutex_t globalMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t globalCond = PTHREAD_COND_INITIALIZER;

pthread_t threads[THREADS_NUM * 2];

void * DoublerThread(void * arg) {
    myStruct * myStr = (myStruct *) arg;
    int id = myStr->cellId;
    pthread_mutex_t mutex = globalMutex;
    pthread_cond_t condition = globalCond;

    pthread_mutex_lock(&mutex);
    while((cells[id] * 2) > MAX) {
        printf("Waiting... id = %d\n", id);
        pthread_cond_wait(&condition, &mutex);
    }
    cells[id] *= 2;
    printf("new val = %d, id = %d\n", cells[id], id);
    pthread_mutex_unlock(&mutex);
    pthread_exit(NULL);
}

void * HalverThread(void * arg) {
    myStruct * myStr = (myStruct *) arg;
    int id = myStr->cellId;
    pthread_mutex_t mutex = globalMutex;
    pthread_cond_t condition = globalCond;
    sleep(1);
    pthread_mutex_lock(&mutex);
    cells[id] /= 2;
    pthread_cond_broadcast(&condition);
    pthread_mutex_unlock(&mutex);
    pthread_exit(NULL);
}

void initMyStructs(myStruct ** myStructs) {
    int i;
    for(i = 0; i < THREADS_NUM * 2; i++) {
        myStructs[i] = (myStruct *) malloc(sizeof(myStruct) * 2);
        if(!myStructs[i]) {
            printf("malloc error\n");
            exit(EXIT_FAILURE);
        }
        myStructs[i]->cellId = i % THREADS_NUM;
    }
}

void initCells() {
    int i, tmp;
    cells =(int *) malloc(sizeof(int));
    if(!cells) {
        printf("malloc error\n");
        exit(EXIT_FAILURE);
    }
    for(i = 0; i <= THREADS_NUM; i++) {
        if(i < THREADS_NUM / 2) {
            cells[i] = MAX - 1;
        } else {
            tmp = cells[i] = 1;
        }
    }
}

int main() {
    int i;
    myStruct ** myStructs;
    initMyStructs(myStructs);
    initCells();

    //create 10 Doubler threads
    for(i = 0; i < THREADS_NUM; i++) {
        pthread_create(&threads[i], NULL, DoublerThread, (void *) myStructs[i]);
    }
    //create 10 Halver threads
    for(i = 0; i < THREADS_NUM; i++) {
        pthread_create(&threads[i + OFFSET], NULL, HalverThread, (void *) myStructs[i + OFFSET]);
    }
    for(i = 0; i < THREADS_NUM + OFFSET; i++) {
        pthread_join(threads[i], NULL);
    }
    return 0;
}

1 Ответ

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

Вы создали «частные» мьютексы и условные переменные для каждого потока, поэтому они не синхронизируются никаким (значимым) способом. Вместо этого:

pthread_mutex_t mutex = globalMutex;
pthread_cond_t condition = globalCond;

Просто используйте globalMutex и globalCond - это то, что вы действительно хотите.

[ Я перенес это сюда, потому что я думаю, что мы должны. Я не могу интуитивно понять SO-Iquette. ]

Кстати, просто чтобы убедиться, что я понимаю это, мьютекс ячейка, так что несколько потоков могут работать на нескольких ячейках одновременно, верно? Просто не две темы в одной ячейке. -

Итак, вы, вероятно, хотите что-то похожее на:

typedef struct myStruct {
    int cellId;
    pthread_mutex_t lock;
    pthread_cond_t  wait;
} myStruct;

и в InitMyStruct ():

myStructs[i]->cellId = i % THREADS_NUM;
pthread_mutex_init(&myStructs[i]->lock, NULL);
pthread_cond_init(&myStructs[i]->wait, NULL);

и в Halvers:

pthread_mutex_lock(&myStr->lock);
cells[id] /= 2;
pthread_cond_broadcast(&myStr->wait);
pthread_mutex_unlock(&myStr->lock);

и удвоитель: ...

   pthread_mutex_lock(&myStr->lock);
    while((cells[id] * 2) > MAX) {
        printf("Waiting... id = %d\n", id);
        pthread_cond_wait(&myStr->wait, &myStr->lock);
    }
    cells[id] *= 2;
    printf("new val = %d, id = %d\n", cells[id], id);
    pthread_mutex_unlock(&myStr->lock);

Так что в настоящее время только один поток может вносить изменения в массив одновременно? Но затем программа завершается примерно через секунду, если потоки не могут вносить изменения в массив одновременно, то не будет Программа занимает 10 секунд, чтобы закончить, потому что каждый HalverThread спит на 1 секунду. - Йос 6 часов

Халверс спят перед тем, как схватить мьютекс, поэтому все спят рядом, просыпаются, сражаются за мьютекс и продолжают.

...