I'm creating simulation of a train station. Train information is read from a file. Each line of the file represents a train and each train gets its own thread. The main track of the train station can only hold 1 train at a time. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <readline/readline.h>
#include <unistd.h>
pthread_mutex_t main_track_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t main_track_condition_var = PTHREAD_COND_INITIALIZER;
int main_track_status = 0;
void *train_function(void *args) {
/* Parse train information */
int line_number = atoi(strtok(args, ":,"));
char *priority_direction = strtok(NULL,":,");
int loading_time = atoi(strtok(NULL, ":,"));
int crossing_time = atoi(strtok(NULL, ":,"));
/* Load train */
sleep(loading_time/10);
printf("Train %d is ready to go %s\n",line_number,priority_direction);
/* If the main track is currently in use, wait for it to become available */
while(main_track_status)
pthread_cond_wait(&main_track_condition_var, &main_track_mutex);
/* Use the main track */
pthread_mutex_lock(&main_track_mutex);
main_track_status = 1;
printf("Train %d is ON the main track going %s\n",line_number,priority_direction);
sleep(crossing_time/10);
main_track_status = 0;
/* Notify other trains main track is empty */
pthread_mutex_unlock(&main_track_mutex);
pthread_cond_signal(&main_track_condition_var);
printf("Train %d is OFF the main track after going %s\n",line_number,priority_direction);
pthread_exit(0);
}
int main() {
FILE *ptr_file;
char buff[10];
int train_count = 0;
char *train;
char line[15];
pthread_t trains[3];
ptr_file = fopen("./trains.txt", "r");
if (!ptr_file)
{
perror("fopen for trains.txt failed");
exit(EXIT_FAILURE);
}
/* Create train for each line of file */
while (fgets(buff,10, ptr_file)!=NULL) {
train = (char*)malloc(10 * sizeof(char));
/* Include line number from file in train information */
sprintf(line, "%d:", train_count);
strcat(line, buff);
strcpy(train, line);
if(pthread_create(&trains[train_count], NULL, &train_function, (void *) train))
{
perror("pthread create failed");
exit(EXIT_FAILURE);
}
train_count++;
}
fclose(ptr_file);
/* Wait for all trains to leave the station */
for (int x = 0; x < train_count; x++) {
pthread_join(trains[x], NULL);
}
free(train);
exit(EXIT_SUCCESS);
}
The trains input file:
e:10,6
W:5,7
E:3,10
The output of the program is:
Train 1 is ready to go W
Train 1 is ON the main track going W
Train 1 is OFF the main track after going W
Train 2 is ready to go E
Train 2 is ON the main track going E
Train 0 is ready to go e
Train 2 is OFF the main track after going E
I think my error lies in the train_function. As you can see, train 0 never gets access to the main track. I must be misunderstanding how threads are awoken with condition variables and am getting stuck in a deadlock. What am I missing?
Yes, you have a slight misunderstanding of pthread_cond_wait. The man page says:
The pthread_cond_timedwait() and pthread_cond_wait() functions shall
block on a condition variable. They shall be called with mutex locked
by the calling thread or undefined behavior results.
These functions atomically release mutex and cause the calling thread
to block on the condition variable cond;
So you need to lock before calling the pthread_cond_wait. That is, your code should be:
/* If the main track is currently in use, wait for it to become available */
pthread_mutex_lock(&main_track_mutex); /* SHOULD LOCK HERE */
while(main_track_status)
pthread_cond_wait(&main_track_condition_var, &main_track_mutex);
/* Use the main track */
//pthread_mutex_lock(&main_track_mutex); /* INCORRECT */
//<..SNIP..>
pthread_mutex_unlock(&main_track_mutex);
pthread_cond_signal(&main_track_condition_var);
Related
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <pthread.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
char mutual[100];
int firstWrote = 0;
int secondWrote = 0;
int firstFinished = 0;
int secondFinished = 0;
void* reader(void* arg)
{
FILE* file = fopen((const char*)arg,"r");
if(file == NULL)
{
printf("Problem with opening file %s",(const char*)arg);
exit(4);
}
else
{
char which[25];
while(fgets(mutual,100,file))
{
pthread_mutex_lock(&mutex);
strcpy(which,(const char*)arg);
if(strcmp(which,"/etc/profile")==0)
{
firstWrote = 1;
//printf("%s\n",mutual);
fflush(stdout);
}
if(strcmp(which,"/etc/passwd")==0)
{
secondWrote = 1;
//printf("%s\n",mutual);
fflush(stdout);
}
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
if(strcmp(which,"/etc/profile")==0)
{
firstWrote = 0;
firstFinished= 1;
}
else if(strcmp(which,"etc/passwd")==0)
{
secondWrote = 0;
secondFinished = 1;
}
}
fclose(file);
pthread_exit(NULL);
}
int main(void)
{
FILE* pawel1 = fopen("PAWEL1","w");
FILE* pawel2 = fopen("PAWEL2","w");
if(pawel1 == NULL || pawel2 == NULL)
{
printf("Problem with opening file");
return 1;
}
pthread_t p1,p2;
pthread_attr_t attr;
if(pthread_attr_init(&attr) != 0)
exit(2);
if(pthread_attr_setd2etachstate(&attr,PTHREAD_CREATE_DETACHED))
exit(3);
pthread_create(&p1,&attr,reader,(void*)"/etc/profile");
pthread_create(&p2,&attr,reader,(void*)"/etc/passwd");
while(1)
{
pthread_mutex_lock(&mutex);
if(firstFinished == 1 && secondFinished == 1)
break;
pthread_cond_wait(&cond,&mutex);
if(firstWrote == 1)
{
fprintf(pawel1,"%s",mutual);
firstWrote = 0;
}
if(secondWrote == 1)
{
fprintf(pawel2,"%s",mutual);
secondWrote = 0;
}
pthread_mutex_unlock(&mutex);
}
fclose(pawel1);
fclose(pawel2);
pthread_attr_destroy(&attr);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
return 0;
}
The app task is to made two different thread read from two files (/etc/passwd and /etc/profile) to a global buffer, and print results to proper file (PAWEL1 or PAWEL2) in main function , and it seems that i handle this behaviour with global flags but what i get is all lines from passwd and profile in one file - PAWEL2, and the file PAWEL1 is left empty.
Since you share a one-line buffer among all threads, including both readers, you must ensure that the main thread runs after each reader thread, never one reader immediately after the other (or itself). Otherwise, one reader can overwrite the data and status flags set by the other. You can accomplish this by
using the existing state flags to determine whose turn it is to run, and
broadcasting to the CV instead of merely signalling it, so that all participating threads get an opportunity to evaluate whether it is appropriate for them to perform a unit of work.
In particular, the rules could look like this:
Readers can run if !firstWrote && !secondWrote, which shows that the buffer is available for new data. They set the appropriate one of those variables after successfully reading the line, thus blocking both readers from overwriting the buffer until its contents are consumed, or they set the appropriate Finished variable and terminate if they cannot read a line.
The main thread can run if firstWrote || secondWrote || (firstFinished && secondFinished). After successfully reading out the buffer, it is responsible for resetting the appropriate one of firstWrote and secondWrote to zero.
When I say a thread "can run", I am talking about the condition associated with each thread's CV wait. The proper idiom for CV usage always involves such a condition, and it looks like this (pseudocode):
lock_mutex()
// ... maybe other code ...
while (condition_is_false()) {
wait_on_cv()
}
// ... maybe other code ...
unlock_mutex()
All accesses to the data that contribute to the condition must be performed under protection from the mutex.
The loop around the wait accounts for two main things:
Control arriving at the condition check when the thread is already clear to proceed
Waking from the wait despite not being clear to proceed, either because of receiving a signal or spuriously (which occasionally does happen)
You can add another level of looping around that (and that would be appropriate for your uses).
Note also that you could simplify your logic considerably by using one set of *Wrote and *Finished variables instead of a separate set for each reader. You would then achieve the necessary distinction among program states by using more values for those variables than just 0 and 1.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to implement the first readers writers problem (reader's preference) in C. I am using mutex locks and unlocks to make sure that no writer can access the thread if a reader has a lock and any reader can access the thread if the first reader has a lock. Here is my code. I am unable to get my code till the end i.e., it is not reaching the thread join part. I guess I am getting a deadlock somewhere or maybe I am placing my mutex locks and unlocks in wrong place.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <fcntl.h>
#include <sys/types.h>
#define FALSE 0
#define TRUE 1
#define SLOWNESS 30000
#define INVALID_ACCNO -99999
#define SIZE 100
#define WRITE_ITR 100000
#define READ_ITR 100000
#define MAX_BALANCE 1000000
typedef struct {
int accno;
float balance;
} account;
// sleep function
void rest()
{
usleep(100);
}
//Global shared data structure
account account_list[SIZE]; /* this is the data structure that the readers and writers will be accessing concurrently.*/
pthread_mutex_t rw_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t r_lock = PTHREAD_MUTEX_INITIALIZER;
/* Writer thread - will update the account_list data structure.
Takes as argument the seed for the srand() function.
*/
void * writer_thr(void * arg)
{
printf("Writer thread ID %ld\n", pthread_self());
srand(*((unsigned int *) arg)); /* set random number seed for this writer */
int i, j;
int r_idx;
unsigned char found; /* For every update_acc[j], set to TRUE if found in account_list, else set to FALSE */
account update_acc[WRITE_ITR];
/* first create a random data set of account updates */
for (i = 0; i < WRITE_ITR;i++)
{
r_idx = rand() % SIZE; /* a random number in the range [0, SIZE) */
update_acc[i].accno = account_list[r_idx].accno;
update_acc[i].balance = 1000.0 + (float) (rand() % MAX_BALANCE);
}//end for
/* open a writer thread log file */
char thr_fname[64];
snprintf(thr_fname, 64, "writer_%ld_thr.log", pthread_self());
FILE* fd = fopen(thr_fname, "w");
if (!fd)
{
fprintf(stderr,"Failed to open writer log file %s\n", thr_fname);
pthread_exit(&errno);
}//end if
/* The writer thread will now try to update the shared account_list data structure.
For each entry 'j' in the update_acc[] array, it will find the corresponding
account number in the account_list array and update the balance of that account
number with the value stored in update_acc[j].
*/
int temp_accno;
for (j = 0; j < WRITE_ITR;j++) {
found = FALSE;
for (i = 0; i < SIZE;i++) {
if (account_list[i].accno == update_acc[j].accno) {
found = 1;
temp_accno = account_list[i].accno;
pthread_mutex_lock(&rw_lock);
account_list[i].accno = INVALID_ACCNO;
account_list[i].balance = update_acc[j].balance;
account_list[i].accno = temp_accno;
rest(); /* makes the write long duration - SO AS TO INTRODUCE LATENCY IN WRITE before going for next 'j' */
pthread_mutex_unlock(&rw_lock);
fprintf(fd, "Account number = %d [%d]: old balance = %6.2f, new balance = %6.2f\n",
account_list[i].accno, update_acc[j].accno, account_list[i].balance, update_acc[j].balance);
}//end if
if (!found)
fprintf(fd, "Failed to find account number %d!\n", update_acc[j].accno);
} // end test-set for-loop
}
fclose(fd);
return NULL;
}
/* Reader thread - will read the account_list data structure.
Takes as argument the seed for the srand() function.
*/
void * reader_thr(void *arg)
{
printf("Reader thread ID %ld\n", pthread_self());
srand(*((unsigned int *) arg)); /* set random number seed for this reader */
int i, j;
int r_idx;
unsigned char found; /* For every read_acc[j], set to TRUE if found in account_list, else set to FALSE */
account read_acc[READ_ITR];
/* first create a random data set of account updates */
for (i = 0; i < READ_ITR;i++)
{
r_idx = rand() % SIZE; /* a random number in the range [0, SIZE) */
read_acc[i].accno = account_list[r_idx].accno;
read_acc[i].balance = 0.0; /* we are going to read in the value */
}//end for
/* open a reader thread log file */
char thr_fname[64];
snprintf(thr_fname, 64, "reader_%ld_thr.log", pthread_self());
FILE *fd = fopen(thr_fname, "w");
if (!fd)
{
fprintf(stderr,"Failed to reader log file %s\n", thr_fname);
pthread_exit(&errno);
}//end if
/* The reader thread will now try to read the shared account_list data structure.
For each entry 'j' in the read_acc[] array, the reader will fetch the
corresponding balance from the account_list[] array and store in
read_acc[j].balance. */
for (j = 0; j < READ_ITR;j++) {
/* Now read the shared data structure */
found = FALSE;
for (i = 0; i < SIZE;i++) {
rest();
if (account_list[i].accno == read_acc[j].accno) {
found = TRUE;
fprintf(fd, "Account number = %d [%d], balance read = %6.2f\n",
account_list[i].accno, read_acc[j].accno, read_acc[j].balance);
pthread_mutex_lock(&r_lock);
if(j == 1)
{
pthread_mutex_lock(&rw_lock);
}
pthread_mutex_unlock(&r_lock);
read_acc[j].balance = account_list[i].balance;
pthread_mutex_lock(&r_lock);
if(j == READ_ITR - 1)
{
pthread_mutex_unlock(&rw_lock);
}
pthread_mutex_unlock(&r_lock);
}
if (!found)
fprintf(fd, "Failed to find account number %d!\n", read_acc[j].accno);
} // end test-set for-loop
}
fclose(fd);
return NULL;
}
/* populate the shared account_list data structure */
void create_testset() {
time_t t;
srand(time(&t));
int i;
for (i = 0;i < SIZE;i++) {
account_list[i].accno = 1000 + rand() % RAND_MAX;
account_list[i].balance = 100 + rand() % MAX_BALANCE;
}
return;
}
void usage(char *str) {
printf("Usage: %s -r <NUM_READERS> -w <NUM_WRITERS>\n", str);
return;
}
int main(int argc, char *argv[])
{
time_t t;
unsigned int seed;
int i;
int READ_THREADS; /* number of readers to create */
int WRITE_THREADS; /* number of writers to create */
if(argc <= 3)
{
usage("./rw");
exit(EXIT_FAILURE);
}
int opt;
while((opt = getopt(argc, argv, "r:w:")) != -1)
{
switch(opt)
{
case 'r':
READ_THREADS = atoi(optarg);
break;
case 'w':
WRITE_THREADS = atoi(optarg);
break;
default:
usage("./rw");
exit(EXIT_FAILURE);
}
}
pthread_t* reader_idx = (pthread_t *) malloc(sizeof(pthread_t) * READ_THREADS); /* holds thread IDs of readers */
pthread_t* writer_idx = (pthread_t *) malloc(sizeof(pthread_t) * WRITE_THREADS); /* holds thread IDs of writers */
/* create readers */
for (i = 0;i < READ_THREADS;i++)
{
seed = (unsigned int) time(&t);
if((pthread_create(&reader_idx[i], NULL, reader_thr, &seed)) != 0)
{
perror("pthread reader create");
exit(-1);
}
}
printf("Done creating reader threads!\n");
/* create writers */
for (i = 0;i < WRITE_THREADS;i++)
{
seed = (unsigned int) time(&t);
/* YOUR CODE GOES HERE */
if((pthread_create(&writer_idx[i], NULL, writer_thr, &seed)) != 0)
{
perror("pthread writer create");
exit(-1);
}
}
printf("Done creating writer threads!\n");
/* Join all reader and writer threads.
*/
for(i = 0; i < READ_THREADS; i++)
{
pthread_join(reader_idx[i], NULL);
}
for(i = 0; i < WRITE_THREADS; i++)
{
pthread_join(writer_idx[i], NULL);
}
printf("Reader threads joined.\n");
printf("Writer threads joined.\n");
pthread_mutex_destroy(&r_lock);
pthread_mutex_destroy(&rw_lock);
return 0;
}
Your code is a mess. There are several things that are wrong with it and each one of them breaks the RW locking mechanism that you are trying to implement.
Both your reader threads and writer threads need to deal with reader exclusion and writer exclusion. Your current code completely ignores the reader exclusion in writer thread.
Your writer thread is reading from the shared structure (if (account_list[i].accno == update_acc[j].accno)) without excluding other writers.
I do not think this is implementable with just mutexes as you seem to be trying to do. E.g., last reader thread out of the critical section needs to be able to let waiting writers go. You probably need at least conditional variables or semaphores to do this.
My suggestion is to use the POSIX pthread_rwlock_init and friends instead.
If you insist on doing this yourself then please read at least this Concurrent Control with "Readers" and "Writers" paper for inspiration on how this can be implemented.
I am trying to create two threads resembling TaskA and TaskB. Both TaskA and TaskB do some kind of computation that it is not very interesting for this post. TaskA and TaskB have to be executed 10 times in order to cover the whole array. TaskA has an input AA and an output BB. BB is also the input of TaskB. CC is the output of TaskB. Because BB is written by taskA and read by taskB we need mutexes.
The behavior I would like to achieve is that when TaskA operates on i, TaskB operates on i-1 in parallel, where i is the number of arrays that are processed.
I want to avoid TaskB to wait for TaskA to finish for every i.
The problem here is that I have a deadlock. ThreadA and ThreadB represent TaskA and TaskB. To make it easier I removed all the computations and I left only synchronization instructions. The deadlock is caused because ThreadA signals the conditional variable CV[0] before threadB is in the state that waits for CV[0].
Do you know any way to remove the deadlock but without TaskA waiting for TaskB to finish and vice versa. Ideally when TaskA operates on array i TaskB should operate on array i-1.
/* Includes */
#include <unistd.h> /* Symbolic Constants */
#include <sys/types.h> /* Primitive System Data Types */
#include <errno.h> /* Errors */
#include <stdio.h> /* Input/Output */
#include <stdlib.h> /* General Utilities */
#include <pthread.h> /* POSIX Threads */
#include <string.h> /* String handling */
#include <semaphore.h> /* Semaphore */
#include <stdint.h>
#define ARRAY_SIZE 2048*2400
#define DEBUG
//#define CHECK_RESULTS
pthread_mutex_t mutex[10];
pthread_cond_t cv[10];
/* prototype for thread routine */
void threadA ( void *ptr );
void threadB ( void *ptr );
struct thread_arg
{
uint32_t *in;
uint32_t *out;
uint32_t ID;
};
int main()
{
pthread_t pthA;
pthread_t pthB;
//Memory allocation
uint32_t *AA = malloc(10*ARRAY_SIZE*sizeof(uint32_t));
uint32_t *BB = malloc(10*ARRAY_SIZE*sizeof(uint32_t));
uint32_t *CC = malloc(10*ARRAY_SIZE*sizeof(uint32_t));
unsigned int j,i;
// THread Arguments
struct thread_arg arguments[2];
arguments[0].in = AA;
arguments[0].out = BB;
arguments[0].ID = 1;
arguments[1].in = BB;
arguments[1].out = CC;
arguments[1].ID = 2;
//Init arguments data
for (j=0;j<10;j++)
{
for (i=0;i<ARRAY_SIZE;i++)
{
AA[j*ARRAY_SIZE+i] = i;
BB[j*ARRAY_SIZE+i] = 0;
CC[j*ARRAY_SIZE+i] = 99 ;
}
}
//Semaphore and conditional variables init
for (i=0;i<10;i++){
pthread_mutex_init(&mutex[i], NULL);
pthread_cond_init (&cv[i], NULL);
}
pthread_create (&pthA, NULL, (void *) &threadA, (void *) &arguments[0]);
pthread_create (&pthB, NULL, (void *) &threadB, (void *) &arguments[1]);
pthread_join(pthA, NULL);
pthread_join(pthB, NULL);
// Destroy Semaphores and CVs
for (i=0;i<10;i++)
{
pthread_mutex_destroy(&mutex[i]);
pthread_cond_destroy(&cv[i]);
}
// Checking results
exit(0);
} /* main() */
void threadA ( void *ptr )
{
int i;
struct thread_arg *arg = (struct thread_arg *) ptr;
for (i=0;i<10;i++)
{
pthread_mutex_lock(&mutex[i]);
printf("TA: LOCK_M%d \n",i);
pthread_cond_signal(&cv[i]);
printf("TA: SIG_CV%d\n",i);
pthread_mutex_unlock(&mutex[i]);
printf("TA: UNL_M%d\n",i);
}
pthread_exit(0); /* exit thread */
}
void threadB ( void *ptr )
{
int i;
struct thread_arg *arg = (struct thread_arg *) ptr;
for (i=0;i<10;i++)
{
pthread_mutex_lock(&mutex[i]);
printf("TB: WAIT_CV%d\n",i,i);
pthread_cond_wait(&cv[i], &mutex[i]);
printf("TB CV%d_PASSED\n",i);
pthread_mutex_unlock(&mutex[i]);
printf("TB UNL_M%d \n",i);
}
pthread_exit(NULL);
}
As WhozCraig commented, a condition variable needs to be paired with a condition over some shared state, known as a predicate. The mutex is used to protect the shared state.
In this example, your shared state could be an integer that contains the highest index of BB[] that ThreadA has produced. ThreadB then waits for this number to reach the index that it is up to reading. In this design, you only need one mutex and one condition variable. The globals would then be:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
int BB_ready = -1; /* Protected by 'mutex' */
(Using the static PTHREAD_*_INITIALIZER initialisers means that you don't need to bother with pthread_*_init() and pthread_*_destroy()).
The loop in ThreadA would then be:
for (i=0;i<10;i++)
{
/* Process AA[i] into BB[i] here */
/* Now mark BB[i] as ready */
pthread_mutex_lock(&mutex);
printf("TA: LOCK_M%d \n",i);
BB_ready = i;
pthread_cond_signal(&cv);
printf("TA: SIG_CV%d\n",i);
pthread_mutex_unlock(&mutex);
printf("TA: UNL_M%d\n",i);
}
..and in ThreadB:
for (i=0;i<10;i++)
{
/* Wait for BB[i] to be ready */
pthread_mutex_lock(&mutex);
printf("TB: WAIT_CV%d\n",i);
while (BB_ready < i)
pthread_cond_wait(&cv, &mutex);
printf("TB CV%d_PASSED\n",i);
pthread_mutex_unlock(&mutex);
printf("TB UNL_M%d \n",i);
/* Now process BB[i] into CC[i] here */
}
Notice that pthread_cond_signal() is called whenever the shared state has changed, which allows the other thread to wake up and re-check the state, if it's waiting.
The waiting thread always loops around, checking the state and then waiting on the condition variable if the state isn't ready yet.
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);
}
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.