I am quite new to threads and am having difficulty understanding the behavior of the code below. Suppose I use the command line input 10, I would expect the output to be 20, since there are two threads incrementing the value of count ten times each. However the output is not 20 every time I run this program. Below are some of my attempts:
Command line input: 10, Expected output: 20, Actual output: 15
Command line input: 10, Expected output: 20, Actual output: 10
Command line input: 10, Expected output: 20, Actual output: 13
Command line input: 10, Excepted output: 20, Actual output: 20
#include <stdio.h>
#include <pthread.h>
/* The threads will increment this count
* n times (command line input).
*/
int count = 0;
/* The function the threads will perform */
void *increment(void *params);
int main(int argc, char *argv[]) {
/* Take in command line input for number of iterations */
long iterations = (long)atoi(argv[1]);
pthread_t thread_1, thread_2;
/* Create two threads. */
pthread_create(&thread_1, NULL, increment, (void*)iterations);
pthread_create(&thread_2, NULL, increment, (void*)iterations);
/* Wait for both to finish */
pthread_join(thread_1, NULL);
pthread_join(thread_2, NULL);
/* Print the final result for count. */
printf("Count = %d.\n", count);
pthread_exit(NULL);
}
void *increment(void *params) {
long iterations = (long)params;
int i;
/* Increment global count */
for(i = 0; i < iterations; i++) {
count++;
}
pthread_exit(NULL);
}
Your increment is not atomic and you didn't insert any synchronization mechanic, so of course your one of your threads will overwrite count while the other was still incrementing it, causing "losses" of incrementations.
You need an atomic increment function (on Windows, you have InterlockedIncrement for this), or an explicit locking mechanism (like a mutex).
To sum two numbers in assembly usually requires several instructions:
move data into some register
add some value to that register
move the data from the register to some cell in the memory
Thereofore, when the operating system gives your program system time, it does not guarantee that all those operations are done without any interruption. These are called critical sections. Every time you enter such a section, you'd need to syncrhonize the two threads.
This should work:
#include <stdio.h>
#include <pthread.h>
/* The threads will increment this count
* n times (command line input).
*/
int count = 0;
pthread_mutex_t lock;
/* The function the threads will perform */
void *increment(void *params);
int main(int argc, char *argv[]) {
/* Take in command line input for number of iterations */
long iterations = (long)atoi(argv[1]);
pthread_t thread_1, thread_2;
pthread_mutex_init(&lock); //initialize the mutex
/* Create two threads. */
pthread_create(&thread_1, NULL, increment, (void*)iterations);
pthread_create(&thread_2, NULL, increment, (void*)iterations);
/* Wait for both to finish */
pthread_join(thread_1, NULL);
pthread_join(thread_2, NULL);
/* Print the final result for count. */
printf("Count = %d.\n", count);
pthread_mutex_destroy(&lock); //destroy the mutex, its similar to malloc and free
pthread_exit(NULL);
}
void *increment(void *params) {
long iterations = (long)params;
int i;
int local_count = 0;
/* Increment global count */
for(i = 0; i < iterations; i++) {
local_count++;
}
pthread_mutex_lock(&lock); //enter a critical section
count += local_count;
pthread_mutex_unlock(&lock); //exit a critical section
pthread_exit(NULL);
}
Related
Very recently I have started working on pthreads and trying to implement software pipelining with pthreads. To do that I have a written a toy program myself, a similar of which would be a part of my main project.
So in this program the main thread creates and input and output buffer of integer type and then creates a single master thread and passes those buffers to the master thread. The master thread in turn creates two worker threads.
The input and the output buffer that is passed from the main to the master thread is of size nxk (e.g. 5x10 of size int). The master thread iterates over a chunk of size k (i.e. 10) for n (i.e. 5) number of times.
There is a loop running in the master thread for k (5 in here) number of times. In each iteration of k the master thread does some operation on a portion of input data of size n and place it in the common buffer shared between the master and the worker threads. The master thread then signals the worker threads that the data has been placed in the common buffer.
The two worker threads waits for the signal from the master thread if the common buffer is ready. The operation on the common buffer is divided into half among the worker threads. Which means one worker thread would work on the first half and the other worker thread would work on the next half of the common buffer.
Once the worker threads gets the signal from the master thread, each of the worker thread does some operation on their half of the data and copy it to the output buffer. Then the worker threads informs the master thread that their operation is complete on the common buffer by setting flag values. An array of flags are created for worker threads. The master thread keeps on checking if all the flags are set which basically means all the worker threads finished their operation on the common buffer and so master thread can place the next data chunk into the common buffer safely for worker thread's consumption.
So essentially there is communication between the master and the worker threads in a pipelined fashion. In the very end I am printing the output buffer in the main thread. But I am getting no output at all. I have copy pasted my code with full comments on almost all steps.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/time.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdbool.h>
#include <string.h>
#define MthNum 1 //Number of Master threads
#define WthNum 2 //Number of Worker threads
#define times 5 // Number of times the iteration (n in the explanation)
#define elNum 10 //Chunk size during each iteration (k in the explanation)
pthread_mutex_t mutex; // mutex variable declaration
pthread_cond_t cond_var; //conditional variarble declaration
bool completion_flag = true; //This global flag indicates the completion of the worker thread. Turned false once all operation ends
//marking the completion
int *commonBuff; //common buffer between master and worker threads
int *commFlags; //array of flags that are turned to 1 by each worker threads. So worker thread i turns commFlags[i] to 1
// the master thread turns commFlags[i] = 0 for i =0 to (WthNum - 1)
int *commFlags_s;
int counter; // This counter used my master thread to count if all the commFlags[i] that shows
//all the threads finished their work on the common buffer
// static pthread_barrier_t barrier;
// Arguments structure passed to master thread
typedef struct{
int *input; // input buffer
int *output;// output buffer
}master_args;
// Arguments structure passed to worker thread
typedef struct{
int threadId;
int *outBuff;
}worker_args;
void* worker_func(void *arguments);
void *master_func(void *);
int main(int argc,char*argv[]){
int *ipData,*opData;
int i,j;
// allocation of input buffer and initializing to 0
ipData = (int *)malloc(times*elNum*sizeof(int));
memset(ipData,0,times*elNum*sizeof(int));
// allocation of output buffer and initializing to 0
opData = (int *)malloc(times*elNum*sizeof(int));
memset(opData,0,times*elNum*sizeof(int));
pthread_t thread[MthNum];
master_args* args[MthNum];
//creating the single master thread and passing the arguments
for( i=0;i<MthNum;i++){
args[i] = (master_args *)malloc(sizeof(master_args));
args[i]->input= ipData;
args[i]->output= opData;
pthread_create(&thread[i],NULL,master_func,(void *)args[i]);
}
//joining the master thred
for(i=0;i<MthNum;i++){
pthread_join(thread[i],NULL);
}
//printing the output buffer values
for(j =0;j<times;j++ ){
for(i =0;i<elNum;i++){
printf("%d\t",opData[i+j*times]);
}
printf("\n");
}
return 0;
}
//This is the master thread function
void *master_func(void *arguments){
//copying the arguments pointer to local variables
master_args* localMasterArgs = (master_args *)arguments;
int *indataArgs = localMasterArgs->input; //input buffer
int *outdataArgs = localMasterArgs->output; //output buffer
//worker thread declaration
pthread_t Workers[WthNum];
//worker thread arguments declaration
worker_args* wArguments[WthNum];
int i,j;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init (&cond_var, NULL);
counter =0;
commonBuff = (int *)malloc(elNum*sizeof(int));
commFlags = (int *)malloc(WthNum*sizeof(int));
memset(commFlags,0,WthNum*sizeof(int) );
commFlags_s= (int *)malloc(WthNum*sizeof(int));
memset(commFlags_s,0,WthNum*sizeof(int) );
for(i =0;i<WthNum;i++){
wArguments[i] = (worker_args* )malloc(sizeof(worker_args));
wArguments[i]->threadId = i;
wArguments[i]->outBuff = outdataArgs;
pthread_create(&Workers[i],NULL,worker_func,(void *)wArguments[i]);
}
for (i = 0; i < times; i++) {
for (j = 0; j < elNum; j++)
indataArgs[i + j * elNum] = i + j;
while (counter != 0) {
counter = 0;
pthread_mutex_lock(&mutex);
for (j = 0; j < WthNum; j++) {
counter += commFlags_s[j];
}
pthread_mutex_unlock(&mutex);
}
pthread_mutex_lock(&mutex);
memcpy(commonBuff, &indataArgs[i * elNum], sizeof(int));
pthread_mutex_unlock(&mutex);
counter = 1;
while (counter != 0) {
counter = 0;
pthread_mutex_lock(&mutex);
for (j = 0; j < WthNum; j++) {
counter += commFlags[j];
}
pthread_mutex_unlock(&mutex);
}
// printf("master broad cast\n");
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&cond_var);
//releasing the lock
pthread_mutex_unlock(&mutex);
}
pthread_mutex_lock(&mutex);
completion_flag = false;
pthread_mutex_unlock(&mutex);
for (i = 0; i < WthNum; i++) {
pthread_join(Workers[i], NULL);
}
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond_var);
return NULL;
}
void* worker_func(void *arguments){
worker_args* localArgs = (worker_args*)arguments;
//copying the thread ID and the output buffer
int tid = localArgs->threadId;
int *localopBuffer = localArgs->outBuff;
int i,j;
bool local_completion_flag=false;
while(local_completion_flag){
pthread_mutex_lock(&mutex);
commFlags[tid] =0;
commFlags_s[tid] =1;
pthread_cond_wait(&cond_var,&mutex);
commFlags_s[tid] =0;
commFlags[tid] =1;
if (tid == 0) {
for (i = 0; i < (elNum / 2); i++) {
localopBuffer[i] = commonBuff[i] * 5;
}
} else { // Thread ID 1 operating on the other half of the common buffer data and placing on the
// output buffer
for (i = 0; i < (elNum / 2); i++) {
localopBuffer[elNum / 2 + i] = commonBuff[elNum / 2 + i] * 10;
}
}
local_completion_flag=completion_flag;
pthread_mutex_unlock(&mutex);//releasing the lock
}
return NULL;
}
But I have no idea where I have done wrong in my implementation since logically it seems to be correct. But definitely there is something wrong in my implementation. I have spent a long time trying different things to fix it but nothing worked. Sorry for this long post but I am unable to determine a section where I might have done wrong and so I couldn't concise the post. So if anybody could take a look into the problem and implementation and can suggest what changes needed to be done to run it as intended then that it would be really helpful. Thank you for your help and assistance.
There are several errors in this code.
You may start from fixing creation of worker threads:
wArguments[i] = (worker_args* )malloc(sizeof(worker_args));
wArguments[i]->threadId = i;
wArguments[i]->outBuff = outdataArgs;
pthread_create(&Workers[i],NULL,worker_func, (void *)wArguments);
You are initializing worker_args structs but incorrectly - passing pointer to array (void *)wArguments instead of pointers to array elements you just initialized.
pthread_create(&Workers[i],NULL,worker_func, (void *)wArguments[i]);
// ^^^
Initialize counter before starting threads that use it's value:
void *master_func(void *arguments)
{
/* (...) */
pthread_mutex_init(&mutex, NULL);
pthread_cond_init (&cond_var, NULL);
counter = WthNum;
When starting master thread, you incorrectly pass pointer to pointer:
pthread_create(&thread[i],NULL,master_func,(void *)&args[i]);
Please change this to:
pthread_create(&thread[i],NULL,master_func,(void *) args[i]);
All accesses to counter variable (as any other shared memory) must be synchronized between threads.
I think you should use semaphore based producer- consumer model like this
https://jlmedina123.wordpress.com/2014/04/08/255/
I'm trying to alter a bit a code to use 'threads' instead of 'forks'. This is the code I have come up with, but there's an error message, and I'm unsure why.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
#define N 2 /* define the total number of processes we want */
/* Set global variable */
float total=0;
/* compute function just does something. */
int compute()
{
int i;
float oldtotal=0, result=0;
/* for a large number of times just square root and square
the arbitrary number 1000 */
for(i=0;i<2000000000;i++)
{
result=sqrt(1000.0)*sqrt(1000.0);
}
/* Print the result should be no surprise */
printf("Result is %f\n",result);
/* We want to keep a running total in the global variable total */
oldtotal = total;
total = oldtotal + result;
/* Print running total so far. */
printf("Total is %f\n",total);
return(0);
}
void* thread_procedure(void* param)
{
int i = (int)param;
/* give a message about the proc ID */
printf("Process Id for process %d is %d\n",i,getpid());
/* call the function to do some computation. If we used sleep
The process would simply sleep. We do not want that */
compute();
return NULL;
}
int main()
{
int i, j;
pthread_t thread[N];
float result=0;
printf("\n"); /* bit of whitespace */
/* We want to loop to create the required number of processes
Note carefully how only the child process is left to run */
for(i=0;i<N;i++)
{
/* start new thread and catch it if it/one fails */
j = pthread_create(&thread[i], NULL, &thread_procedure, (void*)i);
if (j)
{
printf("Error");
exit(1);
}
}
/* joining with threads */
for(i=0;i<N;i++)
pthread_join(thread[i], NULL);
/* nothing else to do so end main function (and program) */
return 0;
}
This is the error that I receive, which I am not understanding
practical2b.c: In function ‘thread_procedure’:
practical2b.c:39:10: warning: cast from pointer to integer of different size
[-Wpointer-to-int-cast]
int i = (int)param;
^
practical2b.c: In function ‘main’:
practical2b.c:62:59: warning: cast to pointer from integer of different size
[-Wint-to-pointer-cast]
j = pthread_create(&thread[i], NULL, &thread_procedure, (void*)i);
^
/tmp/cc9tHCVO.o: In function `main':
practical2b.c:(.text+0x11c): undefined reference to `pthread_create'
practical2b.c:(.text+0x168): undefined reference to `pthread_join'
collect2: error: ld returned 1 exit status
After fixing all the errors/warnings raised by the compiler
and incorporating some of the earlier comments,
this is what the code would look like:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#define N 2 /* define the total number of processes we want */
/* Set global variable */
float total=0.0f;
/* compute function just does something. */
int compute()
{
int i;
float result=0.0f;
/* for a large number of times just square root and square
the arbitrary number 1000 */
for(i=0;i<2000000000;i++)
{
result=sqrt(1000.0)*sqrt(1000.0);
}
/* Print the result should be no surprise */
printf("Result is %f\n",result);
/* We want to keep a running total in the global variable total */
total += result;
/* Print running total so far. */
printf("Total is %f\n",total);
return(0);
} // end function: compute
void* thread_procedure(void* param)
{
int i = *(int*)param;
/* give a message about the proc ID */
printf("Process Id for process %d is %d\n",i,getpid());
/* call the function to do some computation. If we used sleep
The process would simply sleep. We do not want that */
compute();
return NULL;
}
int main()
{
int i, j;
pthread_t thread[N];
printf("\n"); /* bit of whitespace */
/* We want to loop to create the required number of processes
Note carefully how only the child process is left to run */
for(i=0;i<N;i++)
{
/* start new thread and catch it if it/one fails */
j = pthread_create(&thread[i], NULL, &thread_procedure, (void*)&i);
if (j)
{
printf("Error");
exit(1);
}
}
/* joining with threads */
for(i=0;i<N;i++)
pthread_join(thread[i], NULL);
/* nothing else to do so end main function (and program) */
return 0;
} // end function: main
I have written a program which simulates the producer consumer problem and I am running into a couple of issues. This was written using Win32 API.
I am using two semaphores full and empty to perform the counting for the buffer where items are stored. There is a mutex as well to control access to the critical section. I have two functions: one creates an item based on a simple calculation: threads * 1000000 + count, while the other consumes it.
The buffer has 10 spaces in it however the program should hopefully be able to work for different number of spaces and threads. The Producer thread goes through the buffer then starts over until the semaphore counts up to 10. I am running into two problems that I can't seem to find a solution too nor do I get many details in the debugger.
1) The commented part which has the printf() function crashes the thread every single time. Nothing ever gets printed to console. I have tried using just a string as well with no other variables being outputted. No success. I found documentation that printf() can run into trouble when used in a multithreaded environment however in this case it is within the critical section and it crashes on the first try. How can I print that information to console?
2) When I remove the print statements and run the code the threads still crash at different points every time. I can't figure out why. The producer thread is supposed to wait for the empty semaphore and the mutex, put the item in, then increase the count for the full semaphore (signifying an item has been added). When it reaches 10 it should stop. The Consumer thread waits for the full semaphore and the mutex, removes an item, then increases the count for the empty semaphore. Is there something in the way I've written it that is causing these thread exits?
This is what I get:
The program '[5348] OperatingSystem.exe' has exited with code 0 (0x0).
#include<stdio.h>
#include<windows.h>
#include<ctype.h>
#include<tchar.h>
#include<strsafe.h>
#include<conio.h>
#include<time.h>
#define threads 1
#define MAX 10
typedef struct objects {
HANDLE empty;
HANDLE full;
HANDLE mutex;
int buffer[10];
};
struct objects data;
DWORD WINAPI Producers(LPVOID lpParam){
int count = 0;
int item;
while (TRUE){
if (data.buffer[count] == 0){
WaitForSingleObject(data.empty, INFINITE);
WaitForSingleObject(data.mutex, INFINITE);
item = threads * 1000000 + count;
data.buffer[count] = item;
//printf("Producer has produced: %d", item);
ReleaseMutex(data.mutex);
ReleaseSemaphore(data.full, 1, NULL);
}
count++;
if (count == 10){ count = 0; }
};
}
DWORD WINAPI Consumers(LPVOID lpParam){
int count = 0;
while (TRUE){
if (data.buffer[count] != 0){
WaitForSingleObject(data.full, INFINITE);
WaitForSingleObject(data.mutex, INFINITE);
//printf("Consumer has consummed: %d", data.buffer[count]);
data.buffer[count] = 0;
ReleaseMutex(data.mutex);
ReleaseSemaphore(data.empty, 1, NULL);
}
count++;
if (count == 10){ count = 0; }
};
}
int main(int argc, char *argv[]) {
struct objects data;
LONG initialCount = 0;
LONG maxCount = 10;
data.empty = CreateSemaphore(NULL, maxCount, maxCount, NULL);
data.full = CreateSemaphore(NULL, initialCount, maxCount, NULL);
data.mutex = CreateMutex(NULL, FALSE, NULL);
DWORD ConsumerId[threads];
HANDLE ConsumerThread[threads];
DWORD ProducerId[threads];
HANDLE ProducerThread[threads];
for (int i = 0; i < threads; i++){
ProducerThread[i] = CreateThread(
NULL,
0,
Producers,
NULL,
0,
&ProducerId[i]);
ConsumerThread[i] = CreateThread(
NULL,
0,
Consumers,
NULL,
0,
&ConsumerId[i]);
}
}
I am working with a program to write the summation of 1-500 and 500-1000 using two separate threads. I need the output to be written in to a text file which is created by the program itself. When I run the program it creates the file according to the given name, but I am not getting the output as needed. It only writes one single line to the text file. That is the summation of 500-1000. But when I get the output using console it shows the answer as needed. How to overcome this problem. Thanks!
#include <stdio.h>
#include <pthread.h>
#include <fcntl.h>
#include <stdlib.h>
#define ARRAYSIZE 1000
#define THREADS 2
void *slave(void *myid);
/* shared data */
int data[ARRAYSIZE]; /* Array of numbers to sum */
int sum = 0;
pthread_mutex_t mutex;/* mutually exclusive lock variable */
int wsize; /* size of work for each thread */
int fd1;
int fd2;
FILE * fp;
char name[20];
/* end of shared data */
void *slave(void *myid)
{
int i,low,high,myresult=0;
low = (int) myid * wsize;
high = low + wsize;
for(i=low;i<high;i++)
myresult += data[i];
/*printf("I am thread:%d low=%d high=%d myresult=%d \n",
(int)myid, low,high,myresult);*/
pthread_mutex_lock(&mutex);
sum += myresult; /* add partial sum to local sum */
fp = fopen (name, "w+");
//printf("the sum from %d to %d is %d",low,i,myresult);
fprintf(fp,"the sum from %d to %d is %d\n",low,i,myresult);
printf("the sum from %d to %d is %d\n",low,i,myresult);
fclose(fp);
pthread_mutex_unlock(&mutex);
return;
}
main()
{
int i;
pthread_t tid[THREADS];
pthread_mutex_init(&mutex,NULL); /* initialize mutex */
wsize = ARRAYSIZE/THREADS; /* wsize must be an integer */
for (i=0;i<ARRAYSIZE;i++) /* initialize data[] */
data[i] = i+1;
printf("Enter file name : \n");
scanf("%s",name);
//printf("Name = %s",name);
fd1=creat(name,0666);
close(fd1);
for (i=0;i<THREADS;i++) /* create threads */
if (pthread_create(&tid[i],NULL,slave,(void *)i) != 0)
perror("Pthread_create fails");
for (i=0;i<THREADS;i++){ /* join threads */
if (pthread_join(tid[i],NULL) != 0){
perror("Pthread_join fails");
}
}
}
Its because you are opening the same file two times, one on each thread. They are overwriting each other's job.
To solve this you can:
Use the a+ mode on fopen() to append the new line to end of the existing file, or;
Open the file in main() and the threads will only fprintf() to it.
I am trying to get the example code to work such that multiple threads will calculate the sum of successive prime numbers (note that the original author's algorithm for successive prime calculation is very inefficient). So far, running unit tests shows that the output is inconsistent, i.e. it will change slightly each time I run the program. I will post the modified source code in C, along with output for debugging purposes.
Source:
/************************************************************************
* Code listing from "Advanced Linux Programming," by CodeSourcery LLC *
* Copyright(C) 2001 by New Riders Publishing *
* See COPYRIGHT for license information. *
***********************************************************************/
/*
* Modified By : Dylan Gleason
* Class : CST 352 - Operating Systems
* Date : 10/18/2012
*/
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#define DEBUG 0 /* Set to 1 to enable debug statements */
/* global variables to be accessed by each thread */
int current_sum = 2;
int primes_to_compute = 0;
/* create mutex for ensuring serial access to global data */
int thread_flag;
pthread_cond_t cond;
pthread_mutex_t lock;
/* print the thread info for debugging purposes */
void print_thread_info()
{
printf("Current thread ID : %u\n",(unsigned int*)pthread_self());
printf("Current sum of primes : %d\n", current_sum);
printf("Current prime to compute : %d\n\n", primes_to_compute);
}
/* initialize the mutex and return an integer value to determine if
initialization failed or not */
int initialize_mutex()
{
int success = 1;
if(pthread_mutex_init(&lock, NULL) == 0 &&
pthread_cond_init(&cond, NULL) == 0)
success = 0;
thread_flag = 0;
return success;
}
/* set the value of the wait thread flag to the value which the client
passes */
void set_thread_flag(int is_waiting)
{
pthread_mutex_lock(&lock); /* lock mutex */
/* set the wait flag value, and then signal in case the prime
function is blocked, waiting for flag to become set. However,
prime function can't actually check flag until the mutex is
unlocked */
thread_flag = is_waiting;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock); /* unlock mutex */
}
void in_wait()
{
while(!thread_flag)
pthread_cond_wait(&cond, &lock);
}
/* Compute successive prime numbers(very inefficiently). Return the
Nth prime number, where N is the value pointed to by *ARG. */
void* compute_prime(void* arg)
{
while(1)
{
pthread_mutex_lock(&lock);
in_wait();
pthread_mutex_unlock(&lock);
int sum;
int factor;
int is_prime = 1;
set_thread_flag(0);
pthread_mutex_lock(&lock);
sum = current_sum;
if(DEBUG)
{
printf("First lock\n");
print_thread_info();
}
pthread_mutex_unlock(&lock);
set_thread_flag(1); /* tell next thread to go! */
/* wait until ready-flag is released from current thread */
pthread_mutex_lock(&lock);
in_wait();
pthread_mutex_unlock(&lock);
/* Test primality by successive division. */
for(factor = 2; factor < sum; ++factor)
{
if(sum % factor == 0)
{
is_prime = 0;
break;
}
}
/* Is this the prime number we're looking for? */
if(is_prime)
{
int number;
set_thread_flag(0);
pthread_mutex_lock(&lock);
/* only decrement primes_to_compute if is greater than zero! */
if(primes_to_compute > 0)
{
--primes_to_compute;
}
if(DEBUG)
{
printf("Second lock\n");
print_thread_info();
}
number = primes_to_compute;
pthread_mutex_unlock(&lock);
set_thread_flag(1);
pthread_mutex_lock(&lock);
in_wait();
pthread_mutex_unlock(&lock);
if(number == 0)
{
set_thread_flag(0);
pthread_mutex_lock(&lock);
void* sum =(void*) current_sum;
if(DEBUG)
{
printf("Third lock\n");
print_thread_info();
}
pthread_mutex_unlock(&lock);
set_thread_flag(1);
return sum;
}
}
set_thread_flag(0);
pthread_mutex_lock(&lock);
++current_sum;
if(DEBUG)
{
printf("Fourth lock\n");
print_thread_info();
}
pthread_mutex_unlock(&lock);
set_thread_flag(1);
}
return NULL;
}
int main(int argc, char* argv[])
{
int prime;
pthread_t tid[5];
/* Check command-line argument count */
if(argc != 2)
{
printf("Error: wrong number of command-line arguments\n");
printf("Usage: %s <integer>\n", argv[0]);
exit(1);
}
/* Check to see if mutex initialized correctly */
if(initialize_mutex() != 0)
{
printf("Mutex initialization failed.\n");
exit(1);
}
primes_to_compute = atoi(argv[1]);
printf("Successive primes to be computed: %d\n\n", primes_to_compute);
/* Execute five different threads to calculate the prime summation */
int t = 0;
set_thread_flag(1);
for(t; t < 5; ++t)
pthread_create(&tid[t], NULL, &compute_prime, NULL);
/* Wait for the prime number thread to complete, then get result. */
t = 0;
for(t; t < 5; ++t)
pthread_join(tid[t],(void*) &prime);
/* Print the largest prime it computed. */
printf("The %dth prime number is %d.\n", atoi(argv[1]), prime);
return 0;
}
Unit test (executing program five times):
Test successive primes up to 100:
Successive primes to be computed: 100
The 100th prime number is 547.
Successive primes to be computed: 100
The 100th prime number is 521.
Successive primes to be computed: 100
The 100th prime number is 523.
Successive primes to be computed: 100
The 100th prime number is 499.
Successive primes to be computed: 100
The 100th prime number is 541.
Note that the output of non-threaded version if the number for successive primes to calculate is 100, the result will always be 541. Clearly I am not able to grok the correct usage of the mutexes above - if someone has more experience in this area I would be very grateful! Also, please note that I am not concerned with the efficiency/correctness of the actual prime number algorithm, but rather the algorithm for making sure that the threads execute properly with consistent results.
Ok, looking at your program I think I see what's going on.
You have a race condition, and a pretty bad one. Which number you're on is determined by the current_sum variable. You access it at the beginning of each loop, but don't increment it until the end of the loop. You need to set and then increment it at the same time within the same mutex lock, otherwise two different threads will be able to pull the same value, and if they pull the same prime value then that prime will be counted twice.
Hope this helps.