使用互斥锁的意外结果

时间:2013-11-25 14:36:53

标签: c linux pthreads

我必须确定使用N个线程在一个整数数组中建立给定值的位置,并在屏幕上显示这些值。我认为我可以通过使用一个存储索引的数组来解决这个问题,并通过一个跟踪找到位置数量的变量来帮助解决这个问题。共享变量,我使用的是互斥量。问题是我在输出上有重复的位置。我做错了什么?

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

#define P 10
#define SIZE (sizeof(elementsList)/sizeof(elementsList[0]))



static int elementsList[] = {   1,2,3,4,5,6,7,8,3,10,11,12,3,14,15,16,17,
                1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
                1,2,3,4,5,6,7,8,9,3,11,12,13,14,3,16,17,
                1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
                1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,3   };

static int positions[SIZE];
pthread_mutex_t mutex;
volatile int count = 0;
static int value_to_be_found;
static pthread_t threads[P];

void *getPositions(void *arg){
    int *argPtr = arg;
    int start = *argPtr;
    int i;


    for(i = start; i < SIZE; i+= P){
        if(elementsList[i] == value_to_be_found){
            pthread_mutex_lock(&mutex);    
            count++;
            positions[count] = i;           
        pthread_mutex_unlock(&mutex);
       }
    }

}

int main(){

    int th;
    int ret;
    int i;
    printf("Enter the value to be found: \n");
    scanf("%d",&value_to_be_found);

    for(th = 0; th < P; th++){
        ret = pthread_create(&threads[th],NULL,&getPositions,&th);
        if(ret){
            printf("Error!\n");
            exit(-1);
        }
    }

    for(th = 0; th < P; th++){
        pthread_join(threads[th],NULL);
    }
    printf("The positions where % was found are: \n",value_to_be_found);
    for(i = 1; i <= count; i++){
        printf("%d. position #%d\n",i,positions[i]);
    }
    return 0;

}

编辑:输入值为3 输出始终不一样,但这是输出之一:

position #2
position #12
position #84
position #36
position #36
position #43
position #53
position #8
position #48
position #19

应该显示的是:

position #70
position #2
position #12
position #43
position #53
position #84
position #36
position #8
position #48
position #19

1 个答案:

答案 0 :(得分:3)

这一行引入了种族关系:

ret = pthread_create(&threads[th], NULL, &getPositions, &th);

当你将th的地址传递给每个帖子时。

然后在下一次迭代中,地址指向的值会发生变化。即使在最后一次迭代中创建的线程获取地址之前,也可能发生这种情况,取消引用它并在此行本地存储值:

int start = *argPtr;

因此无法保证每个帖子都为start存储了不同的值。


脏解决方案 就是将传递给线程函数的指针误用为如下整数:

ret = pthread_create(&threads[th], NULL, &getPositions, (void *)th);

并在线程函数内部执行

int start = (int) argPtr;

只要int短于void *,这就有效。要使用intptr_t作为thstart的类型,请使用intptr_t进行安全查看,因为void *保证与int starts[P] = {0}; ... int(main(void) { ... for(th = 0; th < P; th++) { starts[th] = th; ret = pthread_create(&threads[th], NULL, &getPositions, &start[th]); 的大小相同。


清洁解决方案 将定义一个数组来保存起始值并将i th 元素的地址传递给线程功能:

getPositions()

同样,return函数错过了pthread_join()语句,但这不会导致问题,因为exit()不使用任何线程返回的值。


另外^ 2:代码错过了<stdlib.h>的原型。包括{{1}}以使其到位。