ある数の間の素数を数えるプログラムを作りたいです。素数を保存するために循環キューを作成しました。基本的には、2 つのスレッドが素数を見つけて循環キューに入れ、1 つのスレッドが素数を取り出してカウントします。私のコードから、get_prime() と get_prime2() はエンキューを行い、consumer() は取り出しを行います。問題は、素数を正しくカウントしないことです。進行中、キューがいっぱいであっても、エンキュースレッドの1つが素数をキューに入れようとするため、素数がキューに入れられず、見逃されると思います。
#include <stdio.h>
#include <pthread.h>
#include <math.h>
//queue size
#define QUEUESIZE 1
//a node in a queue
typedef struct queue{
int element[QUEUESIZE+1];
int front;
int rear;
int count;
}queue;
//make a queue
queue q;
pthread_mutex_t mutex_lock;
pthread_cond_t p_cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t c_cond = PTHREAD_COND_INITIALIZER;
//prime count
int count=0;
//prototype
void init_queue(queue *q);
int enqueue(queue *q, int x);
int dequeue(queue *q);
int q_empty(queue *q);
int q_full(queue *q);
void *get_prime();
void *get_prime2();
void *consumer();
int main(int argc, const char * argv[])
{
pthread_t p_thread[2]; //producer thread
pthread_t c_thread; //consumer thread
int status;
init_queue(&q);
pthread_mutex_init(&mutex_lock, NULL);
pthread_cond_init(&p_cond, NULL);
pthread_cond_init(&c_cond, NULL);
pthread_create(&p_thread[0], NULL, get_prime, (void*)NULL);
pthread_create(&p_thread[1], NULL, get_prime2, (void*)NULL);
pthread_create(&c_thread, NULL, consumer, (void*)NULL);
pthread_join(p_thread[0], (void **)&status);
pthread_join(p_thread[1], (void **)&status);
pthread_join(c_thread, (void **)&status);
printf("\nThe number of prime numbers between 1~100000: %d\n", count);
return 0;
}
//queue initialization
void init_queue(queue *q)
{
q->front = 0;
q->rear = QUEUESIZE-1;
q->count = 0;
}
int enqueue(queue *q, int x)
{
if(q_full(q))
{
return -1;
}
else{
q->rear = (q->rear+1) % QUEUESIZE;
q->element[q->rear] = x;
q->count = q->count + 1;
return 0;
}
}
int dequeue(queue *q)
{
int x;
if(q_empty(q))
{
return -1;
}
else
{
x = q->element[q->front];
q->front = (q->front+1) % QUEUESIZE;
q->count = q->count - 1;
}
return x;
}
int q_empty(queue *q)
{
if(q->count <= 0)
return 1;
else
return 0;
}
int q_full(queue *q)
{
if(q->count >=QUEUESIZE)
return 1;
else
return 0;
}
void *get_prime()
{
int i, j; //loop counter
int temp = 0;
for(i=2; i<50; i++)
{
for(j=2; j<=sqrt(i); j++)
{
if(i%j==0){
temp++;
break;
}
}
if(temp==0)
{
pthread_mutex_lock(&mutex_lock);
if(enqueue(&q, i)==-1) //queue full condition
{
pthread_cond_wait(&p_cond, &mutex_lock);
enqueue(&q, i);
printf("%d\t", i);
}
else
printf("%d\t", i);
pthread_cond_signal(&c_cond);
pthread_mutex_unlock(&mutex_lock);
}
temp=0;
}
}
void *get_prime2()
{
int i, j; //loop counter
int temp = 0;
for(i=50; i<100; i++)
{
for(j=2; j<=sqrt(i); j++)
{
if(i%j==0){
temp++;
break;
}
}
if(temp==0)
{
pthread_mutex_lock(&mutex_lock);
if(enqueue(&q, i)==-1) //queue full condition
{
pthread_cond_wait(&p_cond, &mutex_lock);
enqueue(&q, i);
printf("%d\t", i);
}
else
printf("%d\t", i);
pthread_cond_signal(&c_cond);
pthread_mutex_unlock(&mutex_lock);
}
temp=0;
}
}
void *consumer()
{
int isempty;
while(1)
{
pthread_mutex_lock(&mutex_lock);
isempty = dequeue(&q);
if(isempty != -1){
count++;
}
else
pthread_cond_wait(&c_cond, &mutex_lock);
pthread_cond_signal(&p_cond);
pthread_mutex_unlock(&mutex_lock);
}
}