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

时间:2018-05-03 19:31:46

标签: c multithreading pthreads mutex

我在C中使用pthread,以便在int数组上执行两个操作:一个操作使单元格的值加倍,另一个操作将单元格的值减半。如果在将单元格加倍后,其值将变得大于最大允许值,则线程需要等待,直到另一个线程将该单元格的值减半。我初始化数组的方式是前5个单元格的值非常接近允许的最大值,其他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 :(得分:4)

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

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小时

Halvers在抓住互斥锁之前就睡了,因此所有人都在同时睡觉,醒来,争取互斥并继续。