多线程素数发生器

时间:2013-04-01 07:21:08

标签: c multithreading pthreads posix primes

我有:

input1: n to generate primes up to
input2: no of threads to generate primes

我实现了这个并且它有效,但问题是,每个线程都会生成自己的素数列表[2, n]

但我希望两个线程能够完成相同的生成素数的任务,相互切换,而不是独立切换。如何将n划分为线程数?

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

void *BusyWork(void *threadid)
{
long tid;
tid = (long)threadid;
printf("Hello World! It's me, thread # %ld\n", tid);

double s,d;
int n,i,c,k,p,cs,nsqrt;     
printf( "Input an integer n > 1 to generate primes upto this n:   " ); // prompt 
scanf("%d",&n); 
printf( "Entered integer: %d\n",n);
int array[n];
for(i=0;i<n;i++)
    array[i]=0;
s=sqrt(n);
d=floor(s);
nsqrt = (int) d;

for ( c= 2; c <= nsqrt; c++ )// note here < is not working <= is working here.
    {
        if(array[c]==0)
            {
                cs = c*c;
                k=0;
                for(p=cs; p<n; p=(cs+k*c))
                    {
                        k++;
                        array[p] = 1;
                }//for
            }//if
    }//for

    for ( i = 2; i < n; i++ )
    { 
        if (array[i]==0)
        {
            printf("%5d",i);
        }//if
    }// for
    printf("\n");


    printf("Above prime numbers are generated from me i.e. thread # %ld GOOD BYE!!! \n ", tid);


    pthread_exit((void*) threadid);
    }

  int main (int argc, char *argv[])
  {

   //////// time cal ///////////////////

     struct timespec start, finish;
     double elapsed;

      clock_gettime(CLOCK_MONOTONIC, &start);
     /////////////////////////////////////

    int NUM_THREADS;
     printf("Please Input Total Number of Threads you want to make:-  ");
     scanf("%d",&NUM_THREADS);


     pthread_t thread[NUM_THREADS];
     pthread_attr_t attr;
       int rc;
     long t;
     void *status;

       /* Initialize and set thread detached attribute */
     pthread_attr_init(&attr);
       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

      for(t=0; t<NUM_THREADS; t++) {
        printf("Main: creating thread %ld\n", t);
        rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t); 
        if (rc) {
           printf("ERROR; return code from pthread_create() is %d\n", rc);
           exit(-1);
          }
        }

      /* Free attribute and wait for the other threads */
       pthread_attr_destroy(&attr);
      for(t=0; t<NUM_THREADS; t++) {
       rc = pthread_join(thread[t], &status);
      if (rc) {
       printf("ERROR; return code from pthread_join() is %d\n", rc);
       exit(-1);
       }
       printf("Main: completed join with thread %ld having a status of %ld\n",t,  (long)status);
      }

  printf("Main: program completed. Exiting.\n");
   ////////////// time end ////////////////////////
    clock_gettime(CLOCK_MONOTONIC, &finish);

   elapsed = (finish.tv_sec - start.tv_sec);
      elapsed += (finish.tv_nsec - start.tv_nsec) / 1000000000.0;
   printf("Total time spent by the main:  %e \n", elapsed);
    //////////////////////////////////////////////////////////
   pthread_exit(NULL);
     }

2 个答案:

答案 0 :(得分:4)

你想要的远非微不足道。但这是一个思考,研究和测试两个线程的想法。

为此,您需要在两个线程之间“拆分”作业。例如,让第一个线程在[ 2, k ]之间查找素数,并使第二个线程在[ k+1, x ]之间查找素数。

这是微不足道的部分。问题出现了 - 如何查找x? (k很简单 - x / 2)。

您应该研究 - 例如,如何在给定的时间间隔内查找素数的数量。 This可能很有用:它说,您可以使用:

N ~~ x / ln(x)

其中N是素数的数量,小于x。

好吧,我不是数学家,我现在不能给你解决方案,但应该有一种方法,让N找到x

请注意,这适用于大数字。

所以,有了这个,一旦找到x,你就可以在两个线程之间分割作业。

如你所见,这真的远非微不足道,而且找不到xN)的确切(精确)方法。


当然,另一种琐碎的方式(更容易但不那么好)是知道N的范围并将其分成两个区间。或者,找到第一个,比如100个素数并不是什么大问题。但找到第一个1000是别的东西。在这种情况下,您可以为每个+500素数开始额外的线程,例如。


另一个想法是进行研究以找到N - 素数的近似值。这可能会有所帮助:Is there a way to find the approximate value of the nth prime?

答案 1 :(得分:4)

如果我误解了你的帖子,我很抱歉,但我怀疑你误解了多线程是什么。您的代码和最后一个问题表明您认为启动多个相同的线程意味着它们会以某种方式自动将任务分配到它们之​​间。这基本上是不正确的。我们都希望它是,但事实并非如此。

有几种方法。有一种“手动”方法,您可以在问题中利用并行机会,并为每个位编写一个线程(或者使用不同的参数多次启动相同的线程。无论哪种方式,线程+数据都不相同)。然后,您可以并行运行这些线程。实质上,这是Kirol Kirov建议的方法。

对于长循环的数学问题,可以很好地工作的替代方法是使用可以在运行时自动将循环分解为单独线程的编译器。这意味着您编写普通的单线程代码并告诉编译器生成线程,只要它可以确定这样做是安全的。为您节省大量工作,并在适当的情况下产生有效的结果。 Sun C编译器可以在Solaris上执行此操作,而Intel也可以执行此操作(可能仅在Windows上)。一些研究最新和最伟大的可能值得。但是,这不会教你任何关于多线程编程的知识。

另一种方法是使用类似openMPI的东西(我认为)允许你在for循环之前放入#pragma语句来表示你想要并行执行tile循环。有点像英特尔和Sun编译器可以做的手动版本。