我在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;
}
答案 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在抓住互斥锁之前就睡了,因此所有人都在同时睡觉,醒来,争取互斥并继续。