简体   繁体   English

稍微复杂的线程同步

[英]Slightly complicated thread synchronization

Background info: I am Trying to create a C program that allows me to search through several different files (2 in the source) for the largest prime number. 背景信息:我正在尝试创建一个C程序,它允许我搜索最大素数的几个不同文件(源代码中的2个)。 The program is multi-threaded to speed up the process. 该程序是多线程的,以加快过程。 In this program I am preferring computational time rather that wasted time by having a the threads wait until all of the threads have assigned globalLargestPrime. 在这个程序中,我更喜欢计算时间而不是浪费时间让线程等到所有线程都分配了globalLargestPrime。

The problem: I believe that in my program somewhere either the id is not being passed as a parameter properly, or that somewhere my program starves one of the threads. 问题:我相信在我的程序中某个地方或者id没有正确地作为参数传递,或者某个地方我的程序饿死其中一个线程。

The weird part: When I run my program it will run and finish but sometimes it will only spawn one thread, therefore it will not search through both text files. 奇怪的部分:当我运行我的程序时它将运行并完成但有时它只会产生一个线程,因此它不会搜索两个文本文件。 and other times it will spawn both threads and read from both text files 有时它会产生两个线程并从两个文本文件中读取

#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;
}

If anyone Could please give me some insight on the issue it will be appreciated 如果有人可以请给我一些关于这个问题的见解,将不胜感激

Thanks 谢谢

You're passing in the address of the same local variable to the threads. 您将相同局部变量的地址传递给线程。 Since the variable is updated as each thread is created, when a thread starts it will likely read a value that's intended for a different thread: 由于变量在创建每个线程时都会更新,因此当线程启动时,它可能会读取一个用于不同线程的值:

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

What you'll end up with is multiple threads reading using the same FILE* . 您最终会得到的是使用相同FILE*读取的多个线程。

Since you're passing in a simple int you can pass the value directly as the thread parameter: 由于您传入的是一个简单的int,因此您可以直接将该值作为线程参数传递:

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

Then in the thread get the value like so: 然后在线程中获取值如下:

int id = (int)threadID;

There's no need for the condition variable at all in your code (though again - I'm not sure it's causing a problem). 您的代码中根本不需要条件变量(尽管如此 - 我不确定它是否会导致问题)。 Your condition variable tracks whether globalLargestPrime is in use by another thread or not. 您的条件变量跟踪另一个线程是否正在使用globalLargestPrime Coincidentally, the mutex does the same thing! 巧合的是,互斥体做同样的事情! try: 尝试:

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);

Also, your code uses the antipattern of checking for EOF before reading the file: 此外,您的代码在读取文件之前使用了检查EOF的反模式:

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

which is wrong, though I think might be a harmless error in this instance. 这是错误的,虽然我认为在这种情况下可能是一个无害的错误。 See: 看到:

For starters, you are malloc'ing only one byte, and assigning that to an int*. 对于初学者来说,你只需要一个字节,并将其分配给一个int *。 You should be malloc'ing sizeof(int). 你应该是malloc'ing sizeof(int)。

Also, it would be much simpler if each thread would find the largest prime in its own file, then when each thread finishes, take the max of those results. 此外,如果每个线程在其自己的文件中找到最大的素数,那么会更简单,然后当每个线程完成时,取这些结果的最大值。 No sense needing any synchronization between threads this way. 没有必要以这种方式在线程之间进行任何同步

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM