稍微复杂的线程同步

时间:2012-12-02 18:40:46

标签: c linux multithreading conditional mutex

背景资料: 我正在尝试创建一个C程序,它允许我搜索最大素数的几个不同文件(源代码中的2个)。该程序是多线程的,以加快过程。在这个程序中,我更喜欢计算时间而不是浪费时间,让线程等到所有线程都分配了globalLargestPrime。

问题: 我相信在我的程序中某个地方或者id没有被正确地作为参数传递,或者我的程序在某个地方挨饿其中一个线程。

奇怪的部分: 当我运行我的程序时,它将运行并完成但有时它只会产生一个线程,因此它不会搜索两个文本文件。有时它会产生两个线程并从两个文本文件中读取

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
#include <time.h>

pthread_mutex_t mutex;
pthread_cond_t monitor[2];
int globalLargestPrime = 0;
const int numThreads = 2;
FILE *fIN[2];

typedef enum{
  FREE,
  IN_USE
}lrgstPrm;
lrgstPrm monLargestPrime;//create struct

int timed(){
 return time(NULL);
}

int ChkPrim(int n){
  int i;
  int isPrime = 0;
  int root = sqrt(n);
  for(i=2; i<root; i++){
        if(n % i == 0)
          isPrime = 1;
        else
          isPrime = 0;
     }
  return isPrime;
}

void *calc_sqrt(void *threadID){//Create Threads
  int index, currentNum;
  int localLargestPrime = 0;
  int id = *(int *)threadID;
  int thousandsOfTimes = 0;
  //FILE *fIN = fopen("data.txt", "r");

  //printf(PTHREAD_MUTEX_ERRORCHECK);
  //Calculate some sqrts
  while(!feof(fIN[id])){
  for(index = 0; index < 1000; index++ )
  {//Check every thousand times
    fscanf(fIN[id], "%d\n", &currentNum);
    if(currentNum>localLargestPrime)
      if(ChkPrim(currentNum) == 1)
        localLargestPrime = currentNum;
  }

    pthread_mutex_lock(&mutex);

    thousandsOfTimes++;

    while(monLargestPrime == IN_USE)
    pthread_cond_wait(&monitor[id], &mutex);//wait untill mutex is unlocked
    monLargestPrime = IN_USE;
    //Critical Zone
    printf("Entering Critical Zone My ID: %d\n",id);
    if(localLargestPrime > globalLargestPrime)//Check for largest num
      globalLargestPrime = localLargestPrime;
    else
      localLargestPrime = globalLargestPrime;

    for(index = 0; index < numThreads; index++)
      if(index != id)
        pthread_cond_signal(&monitor[id]);//signal all threads that mutex is unlocked
    monLargestPrime = FREE;
    printf("Exiting Critical Zone My ID: %d\n",id);
    pthread_mutex_unlock(&mutex);
 //   printf("done searching thousand times %d My ID: %d\n",thousandsOfTimes, id);
  }
}

void createText(){
  FILE *fOUT = fopen("data.txt", "w");
  int i;
  srand(time(NULL));
  for(i=0; i<10000; i++)
  fprintf(fOUT, "%d\n",rand()%5000);
  fclose(fOUT);
}


int main(){
   printf("This is before creating threads\n");
  int index, timeDiff;
  pthread_t threads[2];
  pthread_mutex_init(&mutex, NULL);
  for(index = 0; index < numThreads; index++)
    pthread_cond_init(&monitor[index], NULL);
  fIN[0] = fopen("data0.txt","r");
  fIN[1] = fopen("data1.txt","r");

  timeDiff = time(NULL);
  //createText();

  for(index = 0; index < numThreads; index++){
    //int *id = malloc(1);
    //*id = index;
    pthread_create(&threads[index],NULL,calc_sqrt,&index);
  }
  for(index = 0; index < numThreads; index++)
    pthread_join(threads[index],NULL);
  printf("This is after creating threads");

  timeDiff = timed() - timeDiff;

  /*Destroy the mutexes & conditional signals*/
  pthread_mutex_destroy(&mutex);
  pthread_cond_destroy(&monitor[0]);
  pthread_cond_destroy(&monitor[1]);


printf("This is the Time %d\n", timeDiff);
printf("This is the Largest Prime Number: %d", globalLargestPrime);
return 0;
}

如果有人能在这个问题上给我一些见解,我们将不胜感激

由于

2 个答案:

答案 0 :(得分:3)

您将同一局部变量的地址传递给线程。由于变量在创建每个线程时都会更新,因此当线程启动时,它可能会读取一个用于不同线程的值:

pthread_create(&threads[index],NULL,calc_sqrt,&index)
                                              ^^^^^^

您最终将使用相同的FILE*读取多个线程。

由于您传入的是一个简单的int,因此您可以直接将该值作为线程参数传递:

pthread_create(&threads[index],NULL,calc_sqrt,(void*)index)

然后在线程中得到如下值:

int id = (int)threadID;

您的代码中根本不需要条件变量(尽管如此 - 我不确定它是否会导致问题)。您的条件变量跟踪另一个线程是否正在使用globalLargestPrime。巧合的是,互斥体做同样的事情!尝试:

pthread_mutex_lock(&mutex);

thousandsOfTimes++;     // not sure why this local variable even exists, 
                        //  much less is in a critical section

//Critical Zone
printf("Entering Critical Zone My ID: %d\n",id);
if(localLargestPrime > globalLargestPrime)//Check for largest num
  globalLargestPrime = localLargestPrime;
else
  localLargestPrime = globalLargestPrime;   // again, not sure why this is here...

printf("Exiting Critical Zone My ID: %d\n",id);
pthread_mutex_unlock(&mutex);

此外,您的代码在读取文件之前使用了检查EOF的反模式:

while (!feof(somefile)) {
    // whatever...
}

这是错误的,虽然我认为在这种情况下可能是一个无害的错误。参见:

答案 1 :(得分:1)

对于初学者来说,你只需要一个字节,并将其分配给一个int *。你应该是malloc'ing sizeof(int)。

此外,如果每个线程在其自己的文件中找到最大的素数,那么会更简单,然后当每个线程完成时,取这些结果的最大值。没有必要以这种方式在线程之间进行任何同步