如何使用 pthreads 以对具有约束的数组执行同时操作?

How to use pthreads in order to perform simultaneous operations on an array with constraint?

我在 C 中使用 pthreads 以便对 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;
}

您为每个线程创建了“私有”互斥锁和条件变量,因此它们没有以任何(有意义的)方式同步。而不是这个:

pthread_mutex_t mutex = globalMutex;
pthread_cond_t condition = globalCond;

只需使用 globalMutex 和 globalCond -- 这就是您真正想要的。

[ 我把它移到这里,因为我认为我们应该这样做。我无法直觉如此礼节。 ]

By the way, just to make sure I understand this, the mutex is per cell, so that multiple threads can work on multiple cells simultaneously, right? Just not two threads on the same cell. –

所以,您可能想要的是:

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);

在减半中:

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);

So currently, only one thread can make changes to the array at a time? But then the program exits after about a second, if threads couldn't be making changes to the array simultaneously then wouldn't the program take 10 seconds to finish, because each HalverThread sleeps for 1 second. – Yos 6 hours

Halvers 在抢到 mutex 之前睡眠,因此所有的 sleep 都在附近同时,醒来,争夺 mutex 并继续。