We have to make a program that simulates the function of a booking system for seats in a theater. We have N_cust clients that call at the telephone center and N_tel people who answer the phone calls. Each call lasts from t_seathigh to t_seatlow seconds. The payment with the credit card is successful with probability P_cardsuccess. The two arguments that the program gets are the number of clients and the seed for rand_r.There is a thread for each client, and the clients have to wait for a person to talk on the phone. My problem is that the program runs but gives a segmentation fault or gets stuck in an infinite loop on the first loop of the function AwesomeThreadFunction.
I thought that maybe I have not handled the variable telefoners correctly since the program sometimes gets stuck in the first loop of the function but I don't know how exactly. I also don't know why I get this segmentation fault. Where exactly does my program try to access not allocated memory.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include "p3170013-p3170115-p3170097-res1.h"
#include <unistd.h>
#define N_seat 250
#define N_tel 8
#define N_seatlow 1
#define N_seathigh 5
#define t_seatlow 5
#define t_seathigh 10
#define P_cardsuccess 0.9
#define C_seat 20.0
#define BILLION 1E9
pthread_mutex_t lock_phone, lock_bank_account,lock_number_of_transfer,lock_wait_time, lock_service_time, lock_plan, lock_screen;
int plan[N_seat];
int phone_count=0,bank_account=0,tid=0,seats=0,telefoners=N_tel;
unsigned int seed;
float avg_wait_time=0,avg_service_time;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* AwesomeThreadFunction(void* vargc){
tid=*(int*)vargc;
struct timespec waitStart, waitEnd;
clock_gettime(CLOCK_REALTIME, &waitStart);
avg_wait_time-=(waitStart.tv_sec+waitStart.tv_nsec/BILLION);
pthread_mutex_lock(&lock_screen);
printf("%d\n",telefoners);
pthread_mutex_unlock(&lock_screen);
pthread_mutex_lock(&lock_phone);
while (telefoners == 0) {
pthread_cond_wait(&cond, &lock_phone);
}
telefoners--;
pthread_mutex_unlock(&lock_phone);
pthread_mutex_lock(&lock_screen);
printf("coooooooool\n");
pthread_mutex_unlock(&lock_screen);
clock_gettime(CLOCK_REALTIME, &waitEnd);
avg_wait_time+=(waitEnd.tv_sec+waitEnd.tv_nsec/BILLION);
struct timespec talkStart, talkEnd;
clock_gettime(CLOCK_REALTIME, &talkStart);
int how_many_seats=rand_r(&seed);
seed=how_many_seats;
how_many_seats=how_many_seats%(N_seathigh-N_seatlow)+N_seatlow;
int how_many_seconds=rand_r(&seed);
seed=how_many_seconds;
how_many_seconds=how_many_seconds%(t_seathigh-t_seatlow)+t_seatlow;
sleep(how_many_seconds);
if(seats==N_seat){
pthread_mutex_lock(&lock_screen);
printf("%d Reservation cancelled because the theater is full\n",*(int*)vargc);
pthread_mutex_unlock(&lock_screen);
}else if(seats+how_many_seats>N_seat){
pthread_mutex_lock(&lock_screen);
printf("%d Reservation cancelled because there are not enough seats available\n",*(int*)vargc);
pthread_mutex_unlock(&lock_screen);
}else{
int c=0,i=0;
pthread_mutex_lock(&lock_number_of_transfer);
pthread_mutex_unlock(&lock_number_of_transfer);
pthread_mutex_lock(&lock_plan);
while(c<how_many_seats){
if(!plan[i]){
plan[i]=tid;
c++;
}
i++;
}
seats+=how_many_seats;
pthread_mutex_unlock(&lock_plan);
int card_success=rand_r(&seed);
seed=card_success;
float tempp=(float)card_success/(float)RAND_MAX;
card_success=(tempp<=P_cardsuccess);
if(!card_success){
pthread_mutex_lock(&lock_screen);
printf("%d Reservation cancelled because the transaction with the credit card was not accepted\n",*(int*)vargc);
pthread_mutex_unlock(&lock_screen);
pthread_mutex_lock(&lock_plan);
c=0;i=0;
while(c<how_many_seats){
if(plan[i]==tid){
plan[i]=0;
c++;
}
pthread_mutex_lock(&lock_screen);
pthread_mutex_unlock(&lock_screen);
i++;
}
seats-=how_many_seats;
pthread_mutex_unlock(&lock_plan);
pthread_mutex_lock(&lock_number_of_transfer);
pthread_mutex_unlock(&lock_number_of_transfer);
}else{
pthread_mutex_lock(&lock_screen);
printf("%d Reservation completed successfully.The number of the transaction is %d, your seats are ",*(int*)vargc,*(int*)vargc);
pthread_mutex_unlock(&lock_screen);
c=0;i=0;
pthread_mutex_lock(&lock_plan);
while(c<how_many_seats){
if(plan[i]==*(int*)vargc){
pthread_mutex_lock(&lock_screen);
printf("%d ",i);
pthread_mutex_unlock(&lock_screen);
c++;
}
i++;
}
pthread_mutex_unlock(&lock_plan);
pthread_mutex_lock(&lock_screen);
printf("and the cost of the transaction is %.2f euros\n",how_many_seats*C_seat);
pthread_mutex_unlock(&lock_screen);
pthread_mutex_lock(&lock_bank_account);
bank_account+=how_many_seats*C_seat;
pthread_mutex_unlock(&lock_bank_account);
}
}
//we assume that the client is fully served when we have also printed out his/her result of the try to book seats
clock_gettime(CLOCK_REALTIME, &talkEnd);
double cow = ( talkEnd.tv_sec - talkStart.tv_sec ) + ( talkEnd.tv_nsec - talkStart.tv_nsec ) / BILLION;
pthread_mutex_lock(&lock_service_time);
avg_service_time+=cow;
pthread_mutex_unlock(&lock_service_time);
pthread_mutex_lock(&lock_phone);
telefoners++;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock_phone);
pthread_exit(0);
}
int main(int argc,char* argv[]){
int i;
for(i=0;i<N_seat;i++){
plan[i] = 0;
}
//if user did not give the correct number of arguments
if(argc!=3){
printf("Wrong number of arguments\n");
return -1;
}
int N_cust=atoi(argv[1]),tel_available=N_tel,err;
i=0;
seed=atoi(argv[2]);
pthread_t *threads=(pthread_t*)malloc(N_cust*sizeof(pthread_t));
int threadid[N_cust];
//if we can't init one of the mutexes
pthread_mutex_init(&lock_phone, NULL);
pthread_mutex_init(&lock_bank_account, NULL);
pthread_mutex_init(&lock_number_of_transfer, NULL);
pthread_mutex_init(&lock_wait_time, NULL);
pthread_mutex_init(&lock_service_time, NULL);
pthread_mutex_init(&lock_plan, NULL);
pthread_mutex_init(&lock_screen, NULL);
//creating the threads
while(i<N_cust){
threadid[i]=i+1;
err = pthread_create(&(threads[i]), NULL, AwesomeThreadFunction, (void*)&threadid[i]); //func name
if (err){
printf("Thread can't be created :[%s]\n", strerror(err));
}
i++;
}
//join the threads
void *status;
for (i = 0; i < N_cust; i++) {
rc = pthread_join(threads[i], &status);
if (rc != 0) {
printf("ERROR: return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("Main: Thread %lu finished with status %d.\n", threads[i], *(int *)status);
}
//final output
for(i=0;i<N_seat;++i){
if(plan[i]){
printf("Seat %d / client %d\n",i+1,plan[i]);
}
}
printf("Total revenue from sales:\t%d\n",bank_account);
printf("Average waiting time:\t%f\n",(float)avg_wait_time/(float)N_cust);
printf("Average service time:\t%f\n",(float)avg_service_time/(float)N_cust);
free(threads);
//Destroy mutexes
pthread_mutex_destroy(&lock_phone);
pthread_mutex_destroy(&lock_bank_account);
pthread_mutex_destroy(&lock_number_of_transfer);
pthread_mutex_destroy(&lock_wait_time);
pthread_mutex_destroy(&lock_service_time);
pthread_mutex_destroy(&lock_plan);
pthread_mutex_destroy(&lock_screen);
pthread_cond_destroy(&cond);
return 0;
}
An immediate problem leading to segfault is in (irrelevant details omitted):
if(seats+how_many_seats>N_seat) {
....
} else {
int c=0,i=0;
pthread_mutex_lock(&lock_plan);
while(c<how_many_seats) {
if(!plan[i]){
plan[i]=tid;
c++;
}
i++;
}
seats+=how_many_seats;
pthread_mutex_unlock(&lock_plan);
The code determines if it can satisfy the request, and happily proceeds to reserving seats. Only then it locks the plan. Meanwhile, between testing for seats+how_many_seats>N_seat and locking the plan, another thread does the same and modifies the plan. After that there is less seats available than the first thread expects, and the while(c<how_many_seats) loop accesses plan off bounds.
I didn't check the rest; I expect other similar problems. The non-volatile globals are very suspicious. In any case, do yourself a favor and use more functions.
Related
Essentially, my program creates 3 threads. The "server" and 2 "workers." The workers are meant to sum the 3 digit positive integers in a 1000 line file (500 numbers per thread). After each worker has summed its part, the server prints each workers total. The only problem is my semaphores are not seeming to work.
Here is a version of my program:
// simple c program to simulate POSIX thread and semaphore
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
// define semaphores
sem_t s1;
FILE *file;
int sum1 = 0, sum2 = 0, num1 = 0, num2 = 0;
// file name
char fileName[10] = "data1.dat";
// server routine
void* server_routine()
{
printf("Server sent signal to worker thread 1\n");
printf("Server sent signal to worker thread 2\n");
sem_wait(&s1);
printf("Server recieved completion signal from worker thread 1\n");
sem_wait(&s1);
printf("Server recieved completion signal from worker thread 2\n\n");
// print the final results
printf("The sum of the first 500 numbers in the file is: %d\n", sum1);
printf("The sum of the last 500 numbers in the file is: %d\n\n", sum2);
pthread_exit(NULL);
}
// thread 1 reoutine
void* t1_routine()
{
printf("Thread 1 recieved signal from server\n");
file = fopen(fileName, "r");
for(int i = 0; i < 500; i++)
{
fscanf(file, "%d", &num1);
sum1 += num1;
}
printf("sum in thread 1: %d\n", sum1);
printf("Thread 1 sends completion signal to server\n");
sem_post(&s1);
pthread_exit(NULL);
}
// thread 2 routine
void* t2_routine()
{
printf("Thread 2 recieved signal from server\n");
file = fopen(fileName, "r");
fseek(file, 500 * 5, SEEK_SET);
for(int i = 0; i < 500; i++)
{
fscanf(file, "%d", &num2);
sum2 += num2;
}
printf("sum in thread 2: %d\n", sum2);
printf("Thread 2 sends completion signal to server\n");
sem_post(&s1);
pthread_exit(NULL);
}
// main function
int main(int argc, char *argv[])
{
// define threads
pthread_t server, t1, t2;
// initialize the semaphore
sem_init(&s1, 0, 0);
if(pthread_create(&server, NULL, &server_routine, NULL) != 0)
{
return 1;
}
if(pthread_create(&t1, NULL, &t1_routine, NULL) != 0)
{
return 2;
}
if(pthread_create(&t2, NULL, &t2_routine, NULL) != 0)
{
return 3;
}
if(pthread_join(server, NULL) != 0)
{
return 4;
}
if(pthread_join(t1, NULL) != 0)
{
return 5;
}
if(pthread_join(t2, NULL) != 0)
{
return 6;
}
// destroy semaphores
sem_close(&s1);
// exit thread
pthread_exit(NULL);
// end
return 0;
}
I've tested with less threads more semaphores as well, with non luck. I've tried different initial semaphore values. The only time I can get the correct output is when I manually wait with sleep(5); but that defeats the purpose of this project.
A few issues ...
Each client thread does its own/private fopen but FILE *file; is global so they overwrite each others values.
We need to make this variable function scoped so each thread has its own private pointer.
There are no fclose calls.
pthread_exit should not be done by the main thread. It is only for threads created with pthread_create.
Otherwise ...
Whichever thread does the fopen last will set the final value.
So, there is a race condition and the effect is the same as if the main thread (prior to pthread_create calls) had done a single fopen, defeating the purpose of each thread doing its own fopen.
Worse yet, a given thread may do the first fopen, then start with fscanf and have its file value changed when the second thread replaces the file value, so weird stuff happens to each thread because they are doing fseek/fscanf on the same FILE * instance.
Having the aforementioned fclose calls would have made the issue more evident.
Here is the refactored code. It is annotated:
// simple c program to simulate POSIX thread and semaphore
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
// define semaphores
sem_t s1;
// NOTE/BUG: each thread opens a different stream, so this must be function
// scoped
#if 0
FILE *file;
#endif
int sum1 = 0,
sum2 = 0,
num1 = 0,
num2 = 0;
// file name
char fileName[10] = "data1.dat";
// server routine
void *
server_routine()
{
printf("Server sent signal to worker thread 1\n");
printf("Server sent signal to worker thread 2\n");
sem_wait(&s1);
printf("Server recieved completion signal from worker thread 1\n");
sem_wait(&s1);
printf("Server recieved completion signal from worker thread 2\n\n");
// print the final results
printf("The sum of the first 500 numbers in the file is: %d\n", sum1);
printf("The sum of the last 500 numbers in the file is: %d\n\n", sum2);
pthread_exit(NULL);
}
// thread 1 reoutine
void *
t1_routine()
{
// NOTE/FIX: this must be function scoped (i.e. private to this thread)
#if 1
FILE *file;
#endif
printf("Thread 1 recieved signal from server\n");
file = fopen(fileName, "r");
for (int i = 0; i < 500; i++) {
fscanf(file, "%d", &num1);
sum1 += num1;
}
printf("sum in thread 1: %d\n", sum1);
printf("Thread 1 sends completion signal to server\n");
sem_post(&s1);
#if 1
fclose(file);
#endif
pthread_exit(NULL);
}
// thread 2 routine
void *
t2_routine()
{
// NOTE/FIX: this must be function scoped (i.e. private to this thread)
#if 1
FILE *file;
#endif
printf("Thread 2 recieved signal from server\n");
file = fopen(fileName, "r");
fseek(file, 500 * 5, SEEK_SET);
for (int i = 0; i < 500; i++) {
fscanf(file, "%d", &num2);
sum2 += num2;
}
printf("sum in thread 2: %d\n", sum2);
printf("Thread 2 sends completion signal to server\n");
sem_post(&s1);
#if 1
fclose(file);
#endif
pthread_exit(NULL);
}
// main function
int
main(int argc, char *argv[])
{
// define threads
pthread_t server, t1, t2;
// initialize the semaphore
sem_init(&s1, 0, 0);
if (pthread_create(&server, NULL, &server_routine, NULL) != 0) {
return 1;
}
if (pthread_create(&t1, NULL, &t1_routine, NULL) != 0) {
return 2;
}
if (pthread_create(&t2, NULL, &t2_routine, NULL) != 0) {
return 3;
}
if (pthread_join(server, NULL) != 0) {
return 4;
}
if (pthread_join(t1, NULL) != 0) {
return 5;
}
if (pthread_join(t2, NULL) != 0) {
return 6;
}
// destroy semaphores
sem_close(&s1);
// exit thread
// NOTE/BUG: only a subthread should do this
#if 0
pthread_exit(NULL);
#endif
// end
return 0;
}
In the code above, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k
UPDATE:
Thank you for the response Craig. I have implemented your suggestions to my own code but nothing seemed to change. I then decided to copy paste your updated code into a c file to test it out and I got the same result. It is as follows (in a separate comment since the output is too long): –
Max
It's hard to compare results because we're using different datasets. I created a perl script to create some data.
Most important is that the sum reported by the given worker matches what the server sees for that worker task.
Then, if we know what each per thread section of the file should sum to, that is another matter.
The per line termination is critical (e.g.): CRLF vs LF (see below)
The actual order of worker sem_post and termination doesn't really matter. It can vary system to system or, even, invocation to invocation. What matters is that the server thread waits for N threads (i.e.) N sem_wait calls before printing any sums.
I've produced an updated version below.
Server does not "signal" a worker. The worker "signals" the server by doing sem_post and the server "receives" it by doing sem_wait
I've create a task/thread struct to hold the sums, thread IDs, etc.
I've generalized the code to allow N threads.
Added check of \n placement (i.e. line width). That is, under linux/POSIX a four digit number would be followed by LF (newline) and length would be 5. But, under windows, it would be CRLF (carriage return/newline) and length would be 6.
Added check of file size to ensure it is exactly the desired/expected length.
Some additional diagnostics.
Here is the updated code:
// simple c program to simulate POSIX thread and semaphore
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
#include <sys/stat.h>
// number of bytes per line
// 5: 4 digits + LF
// 6: 4 digits + CRLF
#ifndef LINEWID
#define LINEWID (4 + 1)
#endif
// number of items / task
#ifndef COUNT
#define COUNT 500
#endif
// define semaphores
sem_t s1;
#if 0
int sum1 = 0,
sum2 = 0,
num1 = 0,
num2 = 0;
#endif
// file name
#if 0
char fileName[10] = "data1.dat";
#else
const char *fileName = "data1.dat";
#endif
// task control
typedef struct {
pthread_t tid; // thread ID
int tno; // thread index/offset
int sum; // sum
} tsk_t;
#define TSKMAX 50
int tskmax; // actual number of tasks
tsk_t tsklist[TSKMAX]; // list of tasks
// loop through all task blocks
#define TSKFORALL \
tsk_t *tsk = &tsklist[0]; tsk < &tsklist[tskmax]; ++tsk
// server routine
void *
server_routine(void *vp)
{
// NOTE/BUG: server does _not_ signal worker
#if 0
printf("Server sent signal to worker thread 1\n");
printf("Server sent signal to worker thread 2\n");
#endif
for (TSKFORALL) {
printf("Server waiting ...\n");
sem_wait(&s1);
printf("Server complete ...\n");
}
// print the final results
for (TSKFORALL)
printf("The sum of task %d is %d\n",tsk->tno,tsk->sum);
return (void *) 0;
}
// thread 1 reoutine
void *
worker_routine(void *vp)
{
FILE *file;
tsk_t *tsk = vp;
printf("Thread %d running ...\n",tsk->tno);
file = fopen(fileName, "r");
fseek(file,tsk->tno * COUNT * LINEWID,SEEK_SET);
tsk->sum = 0;
int num1;
int first = -1;
int last = -1;
for (int i = 0; i < COUNT; i++) {
if (fscanf(file, "%d", &num1) != 1) {
printf("Thread %d fscan error\n",tsk->tno);
break;
}
if (i == 0)
first = num1;
if (i == (COUNT - 1))
last = num1;
tsk->sum += num1;
}
printf("sum in thread %d: %d (first %d, last %d)\n",
tsk->tno, tsk->sum, first, last);
sem_post(&s1);
#if 1
fclose(file);
#endif
return (void *) 0;
}
// main function
int
main(int argc, char **argv)
{
--argc;
++argv;
setlinebuf(stdout);
setlinebuf(stderr);
if (argc != 1)
tskmax = 2;
else
tskmax = atoi(*argv);
if (tskmax > TSKMAX)
tskmax = TSKMAX;
// define threads
pthread_t server;
printf("main: %d tasks\n",tskmax);
printf("main: %d count\n",COUNT);
FILE *file = fopen(fileName,"r");
if (file == NULL) {
printf("main: fopen failure\n");
exit(96);
}
// check alignment
char chr;
fseek(file,LINEWID - 1,0);
fread(&chr,1,1,file);
if (chr != '\n') {
printf("main: newline mismatch -- chr=%2.2X\n",chr);
exit(97);
}
// get the file size
struct stat st;
if (fstat(fileno(file),&st) < 0) {
printf("main: fstat fault\n");
exit(97);
}
// ensure the file has the correct size
off_t size = tskmax * LINEWID * COUNT;
if (st.st_size != size)
printf("main: wrong file size -- st_size=%llu size=%llu\n",
(unsigned long long) st.st_size,
(unsigned long long) size);
fclose(file);
// initialize the semaphore
sem_init(&s1, 0, 0);
// set the offsets
int tno = 0;
for (TSKFORALL, ++tno)
tsk->tno = tno;
if (pthread_create(&server, NULL, &server_routine, NULL) != 0)
return 98;
for (TSKFORALL) {
if (pthread_create(&tsk->tid,NULL,worker_routine,tsk) != 0)
return 1 + tsk->tno;
}
if (pthread_join(server, NULL) != 0) {
return 99;
}
for (TSKFORALL) {
if (pthread_join(tsk->tid, NULL) != 0) {
return 5;
}
}
// destroy semaphores
sem_close(&s1);
// end
return 0;
}
Here is the perl script output that I used to generate the data:
number of tasks 2
element count per task 500
line separater 0A
section 0 sum 124750
section 1 sum 125250
Here is the program output:
main: 2 tasks
Server waiting ...
Thread 0 running ...
Thread 1 running ...
sum in thread 1: 125250 (first 1, last 500)
sum in thread 0: 124750 (first 0, last 499)
Server complete ...
Server waiting ...
Server complete ...
The sum of task 0 is 124750
The sum of task 1 is 125250
Here is the perl script:
#!/usr/bin/perl
# gendata -- generate data
#
# arguments:
# 1 - number of tasks (DEFAULT: 2)
# 2 - number of items / task (DEFAULT: 500)
# 3 - line separater (DEFAULT: \n)
master(#ARGV);
exit(0);
# master -- master control
sub master
{
my(#argv) = #_;
$tskmax = shift(#argv);
$tskmax //= 2;
printf(STDERR "number of tasks %d\n",$tskmax);
$count = shift(#argv);
$count //= 500;
printf(STDERR "element count per task %d\n",$count);
$sep = shift(#argv);
$sep //= "\n";
printf(STDERR "line separater");
foreach $chr (split(//,$sep)) {
$hex = ord($chr);
printf(STDERR " %2.2X",$hex);
}
printf(STDERR "\n");
for ($itsk = 0; $itsk < $tskmax; ++$itsk) {
$val = $itsk;
$sum = 0;
for ($lno = 1; $lno <= $count; ++$lno, ++$val) {
printf("%4d%s",$val,$sep);
$sum += $val;
}
printf(STDERR "section %d sum %d\n",$itsk,$sum);
}
}
I have a project about marriage operations. In this program, a thread called registrar uses marriage function. In this marriage operations, we have brides and grooms. Marriage function does decrease bride count and groom count one by one. But i have a problem while i want to decrease these count.
MAIN.c
#include<pthread.h>
#include<stdlib.h>
#include<stdio.h>
#include<semaphore.h>
#include "bride.h"
#include "groom.h"
pthread_t groomThread;
pthread_t brideThread;
sem_t registrarSemaphore;
pthread_mutex_t lock;
int *groomCount = 14;
int *brideCount = 20;
int *availableRegistrar;
void createBride(int *brideCount) {
pthread_create(&brideThread, NULL, &increaseBrideCount, (void *) brideCount);
}
void createGroom(int *groomCount) {
pthread_create(&groomThread, NULL, &increaseGroomCount, (void *) groomCount);
}
void deleteGroom(int *groomCount) {
pthread_create(&groomThread, NULL, &decreaseGroomCount, (void *) groomCount);
}
void deleteBride(int *brideCount) {
pthread_create(&brideThread, NULL, &decreaseBrideCount, (void *) brideCount);
}
void marriage() {
sem_init(®istrarSemaphore, 0, 2);
while (1) {
sem_getvalue(®istrarSemaphore, &availableRegistrar);
printf("\nAvailable Registrar Number = %d\n", availableRegistrar);
printf("bride %d\n", brideCount);
printf("groom %d\n", groomCount);
if (brideCount > 0 && groomCount > 0) {
sem_wait(®istrarSemaphore);
sem_getvalue(®istrarSemaphore, &availableRegistrar);
printf("Available Registrar %d \n", availableRegistrar);
printf("Marriage Bride %d and Groom %d \n", brideCount, groomCount);
pthread_mutex_lock(&lock);
deleteBride(brideCount);
pthread_mutex_unlock(&lock);
//pthread_join(brideThread, &brideCount);
pthread_mutex_lock(&lock);
deleteGroom(groomCount);
pthread_mutex_unlock(&lock);
//pthread_join(groomThread, &groomCount);
printf("Exiting critical region...\n\n");
/* END CRITICAL REGION */
sem_post(®istrarSemaphore);
}
int random = rand() % 100;
if (random % 7 > 4) {
printf("Bride Created\n");
pthread_mutex_lock(&lock);
createBride(brideCount);
//pthread_join(brideThread, &brideCount);
pthread_mutex_unlock(&lock);
}
if (random % 7 < 2) {
printf("Groom Created\n");
pthread_mutex_lock(&lock);
createGroom(groomCount);
//pthread_join(groomThread, &groomCount);
pthread_mutex_unlock(&lock);
}
pthread_join(brideThread, &brideCount);
pthread_join(groomThread, &groomCount);
for (int i = 0; i < 100000000; i++);
printf("------------------------------");
}
}
int main(void) {
marriage();
}
In pthread_create part, there are some functions as you can see. It defined in .h part. For example in bride.h, there are 2 functions about bride.
BRIDE.H
#ifndef BRIDE_H
#define BRIDE_H
void* increaseBrideCount(void * bride);
void* decreaseBrideCount(void * bride);
#endif
BRIDE.C
#include <pthread.h>
#include "bride.h"
void* increaseBrideCount(void *bride){
int brideCount = (int)bride;
brideCount++;
pthread_exit(brideCount);
}
void* decreaseBrideCount(void* bride){
int brideCount = (int)bride;
brideCount--;
pthread_exit(brideCount);
}
While im creating new bride,i cant send the new value of bride to the function. For example :
I have 20 brides and 14 grooms at first.
I have 2 available registrar
Marraige does.
Bride count = 19, groom count = 13
Then, i want to create new bride.
It count goes to = 1 :( Im trying to make it 20 again.
If you can help, i would be very happy. Thank you
Semaphores are used to make sure only one of the threads that might make a particular change does so at a time. The things being changed in this case are the bride and groom counts, so you need to "protect" them using semaphores. You even seem to have created semaphores for this purpose (brideSemaphore and groomSemaphore); you just need to use them.
By the way: if you use a semaphore only in a single thread, you're wasting your time (as seems to be the case w/ your registrarSemaphore) in marriage()). Either it needs to be used elsewhere as well, or not at all.
I got stuck when I was trying to print the summary of all threads (namely, grand totals of a group of threads).
The C code below runs 10 threads, simulating agents that sell tickets. After running & completing the threads (i.e. after all the tickets are sold), I want to print the list of agents and corresponding number of tickets sold by that agent. However, the main process terminates as soon as it hits the line pthread_exit(NULL) (marked with a preceding comment) and the code does not return to main, where it is supposed to print the grand totals (this block is marked with a comment as well).
Can anyone tell what's wrong with the code?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
struct ThreadArgs {
int thNum;
int *numTickets;
int *soldTickets;
sem_t *lock;
};
void *SellTickets(void *th) {
struct ThreadArgs *thArgs;
int sleepTime;
thArgs = th;
while (1) {
sleepTime = rand();
if (sleepTime % 2) {
usleep(sleepTime % 1000000);
}
sem_wait(thArgs->lock);
if (*thArgs->numTickets == 0) {
break;
}
printf("There are %3d ticket(s). Agent %d sold a ticket.\n", *thArgs->numTickets, thArgs->thNum);
(*thArgs->numTickets)--;
sem_post(thArgs->lock);
(*thArgs->soldTickets)++;
}
sem_post(thArgs->lock);
pthread_exit(NULL);
}
void runThreads(int numAgents, int numTickets, int soldTickets[]) {
struct ThreadArgs thArgs[numAgents];
int agent;
pthread_t th[numAgents];
sem_t lock;
sem_init(&lock, 1, 1);
for (agent = 0; agent < numAgents; agent++) {
thArgs[agent].thNum = agent;
thArgs[agent].soldTickets = &soldTickets[agent];
thArgs[agent].numTickets = &numTickets;
thArgs[agent].lock = &lock;
pthread_create(&th[agent], NULL, SellTickets, &thArgs[agent]);
}
// when debugging, the process terminates here
pthread_exit(NULL);
}
int main() {
int agent, numAgents, numTickets, soldTickets[10];
numAgents = 10;
numTickets = 150;
for (agent = 0; agent < numAgents; agent++) {
soldTickets[agent] = 0;
}
runThreads(numAgents, numTickets, soldTickets);
// the process never executes the following block
for (agent = 0; agent < numAgents; agent++) {
printf("Agent %d sold %d ticket(s).\n", agent, soldTickets[agent]);
}
return 0;
}
pthread_exit() exits a thread, even the "main"-thread.
If main() ends all other thread go down as well.
As the "main"-thread is expected to do some final logging, it should wait until all threads spawned have ended.
To accomplish this in runThreads() replace the call to
pthread_exit(NULL);
by a loop calling pthread_join() for all PThread-IDs as returned by pthread_create().
Also you want to add error checking to all pthread*() calls, as you should do for every function call returning any relevant info, like for example indicating failure of the call.
I am trying to square the numbers 1 - 10,000 with 8 threads. To clarify, I want the 1st thread to do 1^2, 2nd thread to do 2^2, ..., 8th thread to do 8^2, first thread to do 9^2... etc. The problem I am having is that instead of the above happening, each thread computes the squares of 1-10,000.
My code is below. I have marked sections that I'd rather those answering do not modify. Thanks in advance for any tips!
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>
#define NUMBER_OF_THREADS 8
#define START_NUMBER 1
#define END_NUMBER 10000
FILE *f;
void *sqrtfunc(void *tid) { //function for computing squares
int i;
for (i = START_NUMBER; i<=END_NUMBER; i++){
fprintf(f, "%lu squared = %lu\n", i, i*i);
}
}
int main(){
//Do not modify starting here
struct timeval start_time, end_time;
gettimeofday(&start_time, 0);
long unsigned i;
f = fopen("./squared_numbers.txt", "w");
//Do not modify ending here
pthread_t mythreads[NUMBER_OF_THREADS]; //thread variable
long mystatus;
for (i = 0; i < NUMBER_OF_THREADS; i++){ //loop to create 8 threads
mystatus = pthread_create(&mythreads[i], NULL, sqrtfunc, (void *)i);
if (mystatus != 0){ //check if pthread_create worked
printf("pthread_create failed\n");
exit(-1);
}
}
for (i = 0; i < NUMBER_OF_THREADS; i++){
if(pthread_join(mythreads[i], NULL)){
printf("Thread failed\n");
}
}
exit(1);
//Do not modify starting here
fclose(f);
gettimeofday(&end_time, 0);
float elapsed = (end_time.tv_sec-start_time.tv_sec) * 1000.0f + \
(end_time.tv_usec-start_time.tv_usec) / 1000.0f;
printf("took %0.2f milliseconds\n", elapsed);
//Do not modify ending here
}
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.