1

背景信息:我正在尝试创建一个 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;
}

如果有人可以请给我一些关于这个问题的见解,我们将不胜感激

谢谢

4

2 回答 2

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...
}

这是错误的,尽管我认为在这种情况下可能是一个无害的错误。看:

于 2012-12-02T18:54:17.120 回答
1

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

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

于 2012-12-02T18:45:03.647 回答