I've got my code down for a dining philosopher problem, using shared memory. The issue I'm encountering is that 3 of 5 philosophers are eating which shouldn't be happening. Where am I going wrong in my code?
Updated: still not working right. Philosophers seem to not be going through one of the states
#include <stdio.h> // needed for printf, sprintf, ...
#include <stdlib.h> // needed for exit()
#include <unistd.h> // needed for sleep, fork, waitpid, _exit, ftruncate
#include <sys/wait.h> // needed for waitpid
#include <fcntl.h> // For O_* constants
#include <sys/mman.h> // needed for mmap, munmap and associated constants
#include <semaphore.h>
void philosopher(int i);
int parent(void);
void take_forks(int i);
void put_forks(int i);
void test (int i);
void think(int i);
void eat(int i);
#define N 5 /* number of philosophers */
#define THINKING 0 /* philosopher is thinking */
#define HUNGRY 1 /* philosopher is trying to get for ks */
#define EATING 2 /* philosopher is eating */
#define FINISH 3
#define LEFT (arga+4)%N
#define RIGHT (arga+1)%N
struct shared_memory {
int k;
int state[N];
sem_t s[N];
sem_t mutex;
};
struct shared_memory *shared;
int fd_shm, fd_log;
int main(void) {
if ((fd_shm = shm_open ("/test", O_RDWR | O_CREAT, 0660)) == -1)
printf("error");
if (ftruncate (fd_shm, sizeof (struct shared_memory)) == -1)
printf("error");
if ((shared = mmap (NULL, sizeof (struct shared_memory), PROT_READ | PROT_WRITE, MAP_SHARED,fd_shm, 0)) == MAP_FAILED)
printf("error");
// Initialize the shared memory
shared -> k = 0;
for (int i=0; i<N;i++){
shared -> state[i] = 0;
sem_init(&shared->s[i],0,1);
}
sem_init(&shared->mutex,1,1);
pid_t pids[N];
// At the beginning every philosopher is thinking
for (int l = 0; l < N; l++){
shared ->state[l]=THINKING;
}
printf("Start");
for(int j=0; j< N; j++){
if((pids[j] = fork()) < 0){
printf("failed");
perror("fork");
}else if (pids[j] == 0 ){
int pid = getpid();
printf("pids[%d] = %d\n",j,pid);
philosopher(j);
exit(0);
}
}
parent();
for (int m=0; m<N;m++){
waitpid(pids[m],NULL,0);
}
printf("This is final k %d\n",shared->k);
if (munmap(shared, sizeof(struct shared_memory)) == -1) {
printf("Function munmap() failed\n");
exit(-1);
}
if ((shm_unlink("/test")) == -1){
printf("Function shm_unlink() failed\n");
exit(-1);
}
return EXIT_SUCCESS;
}
void philosopher(int arga) {
//int count =0;
//while(count<5){
while(1){
//sleep(1);
//think(i);
take_forks(arga);
sleep(2);
//eat(i);
//sleep(1);
put_forks(arga);
//count++;
}
shared->state[arga] = FINISH;
}
void take_forks(int arga) /* i: philosopher number, from 0 to N−1 */
{
//printf("arga take_fork: %d\n", arga);
sem_wait(&shared->mutex); /* enter critical region, down mutex */
shared->state[arga] = HUNGRY; /* record fact that philosopher i is hungry */
//while (shared->state[i] == HUNGRY){
test(arga); /* try to acquire 2 forks */
sem_post(&shared->mutex); /* exit critical region, up mutex */
//sem_wait(&shared->s[arga]); /* block if forks were not acquired, down philosopher*/
//}
//sleep(1);
}
void put_forks(int arga) /* i: philosopher number, from 0 to N−1 */
{
//printf("arga put_fork: %d\n", arga);
sem_wait(&shared->mutex); /* enter critical region, down mutes */
//test(LEFT); /* see if left neighbor can now eat */
//test(RIGHT); /* see if right neighbor can now eat */
shared->state[arga] = THINKING; /* philosopher has finished eating */
sem_post(&shared->mutex); /* exit critical region, up mutex */
}
void test(int arga) /* i: philosopher number, from 0 to N−1 */
{
sem_wait(&shared->s[LEFT]);
sem_wait(&shared->s[RIGHT]);
shared->state[arga]= EATING;
sleep(1);
sem_post(&shared->s[RIGHT]);
sem_post(&shared->s[LEFT]);
//if (shared->state[arga] == HUNGRY && shared->state[LEFT] != EATING && shared->state[RIGHT] != EATING)
//{
//printf("Philosopher: %d (i+N-1)%N - %d", i, ((i+N-1)%N));
//shared->state[arga] = EATING;
//sleep(2);
//sem_post(&shared->s[arga]); //Up philosopher
//}
}
void think(int arga){
//printf("I am philosopher %d i am thinking\n", i);
sleep(2);
}
void eat(int arga){
//printf("I am philosopher %d i am eating\n", i);
sleep(3);
}
int parent(void){
puts("This is the Parent Process");
int philosopherState;
char* philprint;
int count=0;
int c;
while (1){
sleep(1);
//sem_wait(&shared->mutex);
for(int o = 0; o<N;o++ ){
/*philosopherState = shared->state[o];
if (philosopherState == 0) {
philprint = "Thinking";
}else if(philosopherState == 1){
philprint = "Eating";
}else if(philosopherState == 2){
philprint = "Hungry";
}else if(philosopherState == 3){
philprint = "Gone";
count++;
}*/
sem_getvalue(&shared->s[o], &c);
//printf("P%d %s \t",o, philprint);
if (c==0){
printf("P%d Thinking\t",o);
}
else if(c==1){
printf("P%d Eating\t",o);
}
else if (c==2){
printf("P%d Hungry\t",o);
}
else if (c==3){
printf("P%d Gone\t",o);
}
if (count >4){
break;
}
}
//sem_post(&shared->mutex);
printf("\n");
}
return 0;
}
//while(count<5){
while(1){
//sleep(1);
//think(i);
take_forks(arga);
sleep(2);
//eat(i);
//sleep(1);
put_forks(arga);
//count++;
}
shared->state[arga] = FINISH;
}
void take_forks(int arga) /* i: philosopher number, from 0 to N−1 */
{
//printf("arga take_fork: %d\n", arga);
sem_wait(&shared->mutex); /* enter critical region, down mutex */
shared->state[arga] = HUNGRY; /* record fact that philosopher i is hungry */
//while (shared->state[i] == HUNGRY){
test(arga); /* try to acquire 2 forks */
sem_post(&shared->mutex); /* exit critical region, up mutex */
//sem_wait(&shared->s[arga]); /* block if for ks were not acquired, down philosopher*/
//}
//sleep(1);
}
void put_forks(int arga) /* i: philosopher number, from 0 to N−1 */
{
//printf("arga put_fork: %d\n", arga);
sem_wait(&shared->mutex); /* enter critical region, down mutes */
//test(LEFT); /* see if left neighbor can now eat */
//test(RIGHT); /* see if right neighbor can now eat */
shared->state[arga] = THINKING; /* philosopher has finished eating */
sem_post(&shared->mutex); /* exit critical region, up mutex */
}
void test(int arga) /* i: philosopher number, from 0 to N−1 */
{
sem_wait(&shared->s[LEFT]);
sem_wait(&shared->s[RIGHT]);
shared->state[arga]= EATING;
sleep(1);
sem_post(&shared->s[RIGHT]);
sem_post(&shared->s[LEFT]);
//if (shared->state[arga] == HUNGRY && shared->state[LEFT] != EATING && shared->state[RIGHT] != EATING)
//{
//printf("Philosopher: %d (i+N-1)%N - %d", i, ((i+N-1)%N));
//shared->state[arga] = EATING;
//sleep(2);
//sem_post(&shared->s[arga]); //Up philosopher
//}
}
void think(int arga){
//printf("I am philosopher %d i am thinking\n", i);
sleep(2);
}
void eat(int arga){
//printf("I am philosopher %d i am eating\n", i);
sleep(3);
}
int parent(void){
puts("This is the Parent Process");
int philosopherState;
char* philprint;
int count=0;
//int c;
while (1){
sleep(1);
for(int o = 0; o<N;o++ ){
philosopherState = shared->state[o];
if (philosopherState == 0) {
philprint = "Thinking";
}else if(philosopherState == 1){
philprint = "Eating";
}else if(philosopherState == 2){
philprint = "Hungry";
}else if(philosopherState == 3){
philprint = "Gone";
count++;
}
//sem_getvalue(&shared->s[o], &c);
printf("P%d %s \t",o, philprint);
//printf("P%d %s\t",o, c == 0 ? "Eating" : "Hungry");
if (count >4){
break;
}
}
printf("\n");
}
return 0;
}
Related
The product type should be 1 or 2 depending on the process that created the product
product id should increase by one each time one is produced
consumer id will always be 1,2,3, or 4 depending on which thread consumer consumes the product
consumer count will increase by 1 each time one is consumed
And product type should only be 1 or 2
i think i need to change the code up a bit and add condition variables and locks .But stuck at that
I have most of it done but it has some issues.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <stdbool.h>
#include <fcntl.h>
#include <pthread.h>
#define BUFFER_SIZE1 20
#define BUFFER_SIZE2 30
typedef struct
{
int count;
int productType;
} product;
int count = 0;
int fd[2];
pthread_mutex_t lock;
pthread_cond_t cond;
typedef struct
{
product *values;
int head;
int tail;
int numEntries;
int size;
} queue;
queue q1;
queue q2;
void producer(int args);
void *consumer(void *args);
void *distributor(void *args);
void initQ(queue *q, int size);
bool QEmpty(queue *q);
bool QFull(queue *q);
bool put(queue *q, product prod);
product get(queue *q);
// https://www.youtube.com/watch?v=l6zkaJFjUbM
// https://www.geeksforgeeks.org/multithreading-c-2/
int main(int argc, char const *argv[])
{
// Creating 5 threads 4 consumer and 1 distributor
pthread_t th[5];
// Creating our pipe, fd[0] is read end, fd[1] is write end
if (pipe(fd) == -1)
{
perror("error creating pipe");
exit(1);
}
// Initializing both buffers
initQ(&q1, BUFFER_SIZE1);
initQ(&q2, BUFFER_SIZE2);
int pid1;
int pid2;
int consId1 = 1;
int consId2 = 2;
// Initializing lock
pthread_mutex_init(&lock, NULL);
// Initialziing condition variables
pthread_cond_init(&cond, NULL);
// Create first producer process using fork(), child process 1
pid1 = fork();
if (pid1 == 0)
{
producer(1);
}
// Create second prodcuer process using fork(), child process 2
pid2 = fork();
if ( pid2== 0)
{
producer(2);
}
// Create distrubtor and consumer threads, parent process
else
{
// Creating 4 threads using for loop and pthread_create
for (int i = 0; i < 4; i++)
{
// 2 consumer threads for product type 1
if (i == 1 || i == 2)
{
if (pthread_create(&th[i], NULL, &consumer, &consId1) != 0)
{
perror("Error creating thread");
}
}
// 2 consumer threads for product type 2
else
{
if (pthread_create(&th[i], NULL, &consumer, &consId2) != 0)
{
perror("Error creating thread");
}
}
}
// use pthread_join to wait for preivous thread to terminate
for (int i = 0; i < 4; i++)
{
if (pthread_join(th[i], NULL) != 0)
{
perror("Error joining thread");
}
}
// Distributor thread
close(fd[1]);
while (1)
{
product prod;
// Using lock and condition variable around crit section to avoid race condition
// pthread_mutex_lock(&lock);
// pthread_cond_wait(&cond, &lock);
// Read from the pipe
read(fd[0], &prod, sizeof(prod));
if (prod.productType == 1)
{
put(&q1, prod);
}
else
{
put(&q2, prod);
}
}
// pthread_cond_signal(&cond);
// pthread_mutex_unlock(&lock);
// Close read end of the pipe
close(fd[0]);
}
return 0;
}
// Creating the producers
void producer(int args)
{
int prodCount = 0;
product prod;
prod.productType = args;
// Close read end of the pipe
close(fd[0]);
while (1)
{
prodCount++;
prod.count = prodCount;
// Send product to the pipe so the consumer can use
write(fd[1], &prod, sizeof(prod));
// Sleep for 0.01 - 0.2 seconds after each loop
int time = (rand() % (200000 - 10000 + 1)) + 10000;
usleep(time);
}
// Close write end of the pipe
close(fd[1]);
}
void *consumer(void *args)
{
int consCount1;
int consCount2;
FILE *fp;
fp = fopen("output.txt", "w");
product prod;
int prodType = *(int *)args;
while (1)
{
if (prodType == 1)
{
get(&q1);
consCount1++;
fputs("Thread ID: \n", fp);
fprintf(fp, "Product Type: %d\n", prod.productType);
fprintf(fp, "Production Sequence #: %d\n", prod.count);
fprintf(fp, "Consumption Sequence #: %d\n", consCount1);
}
else
{
get(&q2);
consCount2++;
fputs("Thread ID: 2\n", fp);
fprintf(fp, "Product Type: %d\n", prod.productType);
fprintf(fp, "Production Sequence #: %d\n", prod.count);
fprintf(fp, "Consumption Sequence #: %d\n", consCount2);
}
}
fclose(fp);
}
// https://www.youtube.com/watch?v=oyX30WVuEos&t=196s
// Circular buffer
void initQ(queue *q, int size)
{
q->size = size;
q->values = malloc(sizeof(product) * q->size);
q->numEntries = 0;
q->head = NULL;
q->tail = NULL;
}
// Checks if the queue is empty
bool QEmpty(queue *q)
{
return (q->numEntries == 0);
}
// Checks if the queue is full
bool QFull(queue *q)
{
return (q->numEntries == q->size);
}
// Used for adding products to the queue
bool put(queue *q, product prod)
{
// If the queue is full we can not add to it
if (QFull(q))
{
return false;
}
// Add product to the end of the queue
q->values[q->tail] = prod;
q->numEntries++;
// Move index of the tail
q->tail = (q->tail + 1);
// If index goes out of bounds set back to 0
if (q->tail >= q->size)
{
q->tail = 0;
}
return true;
}
// Used for removing products for the queue
product get(queue *q)
{
product result;
// If the queue is empty we can not dequeue anymore
if (QEmpty(q))
{
perror("Error on dequeue");
}
// Remove from the head of the queue
result = q->values[q->head];
q->head = (q->head + 1) & q->size;
q->numEntries--;
return result;
}
I have the following program:
#include <stdio.h>
#include <sys/types.h>
#define MAX_COUNT 100
void ChildProcess(void);
void ParentProcess(void);
void main(void)
{
pid_t pid;
pid = fork();
if (pid == 0)
ChildProcess();
else
ParentProcess();
}
void ChildProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf(" This line is from child, value = %d\n", i);
printf(" *** Child process is done ***\n");
}
void ParentProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf("This line is from parent, value = %d\n", i);
printf("*** Parent is done ***\n");
}
I have to modify it in a way that both the parent and the child print stored data from the shared memory in the following way:
Create and initialize the shared memory in the parent.
Fill the shared memory with 5 integer numbers. (I should allocate enough shared memory to store the 5 ints.)
Fork from the parent to the child.
If fork is successful, then the child process must print the values stored in the shared memory as shown in the expected output where N1, N2, N3, N4, N5 are the numbers found in the shared memory.
Expected output
What I did in the ParentProcess function is the following:
void ParentProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf("This line is from parent, value = %d\n", i);
printf("*** Parent is done ***\n");
int localVar = 0;
int* p = (int*) malloc(2);
pid_t childPID = fork();
*p = 0;
if (childPID >= 0)
{
printf("\nChild process has started\n");
if (childPID == 0)
{
localVar++;
globalVar++;
printf("Child process has found the following data %d,", *p);
*p = 70;
printf( " %d,", *p);
*p = 66;
printf(" %d,", *p);
*p = 51;
printf(" %d,", *p);
*p = 90;
printf(" %d in shared memory\n",*p);
printf("Child is existing\n\n");
}
}
}
And now I realize that I did it completely wrong but I have no idea how to fix that. I suppose I have to use shmget to create the shared memory, but then what? How do I store values in it?
If you find that you cannot help me with this or it is too long, please share sources where I can learn more about C programming in Linux, particularly regarding the usage of shared memory. Thank you in advance
It may be better to make it clear what you want to do first because as far as I read your code you call fork() twice in your code (once in main() function and once in ParentProcess() function)
So I write general solution for parent/child shared memory. There are several ways to achieve shared memory but this is one example which is modified version of the code here
How to use shared memory with Linux in C
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
void *create_shared_memory(size_t size)
{
int protection = PROT_READ | PROT_WRITE;
int visibility = MAP_SHARED | MAP_ANONYMOUS;
return mmap(NULL, size, protection, visibility, -1, 0);
}
int main()
{
// Allocate 4 ints
void *shmem = create_shared_memory(sizeof(int)*4);
if( shmem == NULL ){
fprintf(stderr, "Failed to create shared memory\n");
return -1;
}
// Initialize 4 ints
((int*)shmem)[0] = 10;
((int*)shmem)[1] = 100;
((int*)shmem)[2] = 1000;
((int*)shmem)[3] = 10000;
int pid = fork();
if (pid == 0)
{
// Print 4 ints in child
printf("Child reading int 0: %d\n", ((int*)shmem)[0]);
printf("Child reading int 1: %d\n", ((int*)shmem)[1]);
printf("Child reading int 2: %d\n", ((int*)shmem)[2]);
printf("Child reading int 3: %d\n", ((int*)shmem)[3]);
printf("Child end\n");
}
else
{
printf("Parent waiting for child ends...\n");
waitpid(pid, NULL, 0);
printf("Parent ends\n");
}
int ret = munmap(shmem, sizeof(int)*4);
if( ret != 0 ){
fprintf(stderr, "Failed to unmap shared memory\n");
return -1;
}
return 0;
}
I've written a small piece of c code which you might find helpful:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define NUM_INTS 5
int main(int argc, char *argv[])
{
key_t key = (key_t) 123456;
int shmgetrc, semgetrc;
struct shmid_ds ds;
int *shared_values;
int i;
struct sembuf sops[2];
int semid;
sops[0].sem_num = 0; /* Operate on semaphore 0 */
sops[0].sem_op = 0; /* Wait for value to equal 0 */
sops[0].sem_flg = 0;
sops[1].sem_num = 0; /* Operate on semaphore 0 */
sops[1].sem_op = 1; /* Increment value by one */
sops[1].sem_flg = 0;
/* create SHM segment */
shmgetrc = shmget(key, NUM_INTS * sizeof(int), IPC_CREAT | IPC_EXCL | 0x180);
if (shmgetrc < 0) {
perror("shmget failed...");
exit(1);
}
/* retrieve the address of the segment */
shared_values = (int *) shmat(shmgetrc, NULL, 0);
/* create a semaphore */
semgetrc = semget(key, 1, IPC_CREAT | IPC_EXCL | 0x180);
if (semgetrc < 0) {
perror("semget failed...");
exit(1);
}
/* lock the semaphore */
if (semop(semgetrc, sops, 2) == -1) {
perror("semop lock failed ...");
exit(1);
}
/* fill it with values */
for (i = 0; i < NUM_INTS; ++i) {
shared_values[i] = i;
}
/* unlock the semaphore */
sops[0].sem_op = -1;
if (semop(semgetrc, sops, 1) == -1) {
perror("semop release failed ...");
exit(1);
}
/* here something else could happen */
sleep(60);
/* lock the semaphore */
sops[0].sem_op = 0;
if (semop(semgetrc, sops, 2) == -1) {
perror("semop lock failed ...");
exit(1);
}
/* print values */
for (i = 0; i < NUM_INTS; ++i) {
printf("%d ", shared_values[i]);
}
printf("\n");
/* unlock the semaphore */
sops[0].sem_op = -1;
if (semop(semgetrc, sops, 1) == -1) {
perror("semop release failed ...");
exit(1);
}
/* remove the semaphore */
if (semctl(semgetrc, semgetrc, IPC_RMID) < 0) {
perror("semctl failed ...");
exit(1);
}
/* remove shm segment again */
if (shmctl(shmgetrc, IPC_RMID, &ds) < 0) {
perror("shmctl failed ...");
exit(1);
}
exit(0);
}
It was not my intention to write the most beautiful code ever written, just an example that shows:
how to create a shm segment
how to retrieve the address and to use it
how to remove it
Additionally, I've used a semaphore to protect the access.
Contrary to the other answer, I've used the ipc interface, not mmap().
When the thread goes to perform_work() to make a new pid, it spits out a segmentation fault when it tries to do it a second time. I must be configuring my thread creation wrong but I'm not sure where. This question is a follow up to: Modify PID manager for multi-threading
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
#define MIN_PID 300
#define MAX_PID 5000
#define CB CHAR_BIT
#define NUM_THREADS 20
int sz = MAX_PID - MIN_PID + 1;
int id;
int i;
int map;
unsigned char *unsignedChar;
int allocate_map();
int allocate_pid();
void *perform_work();
void release_pid(int pid);
int main()
{
pthread_t threads[NUM_THREADS];
int thread_args[NUM_THREADS];
int result_code, index;
//create all threads one by one
for (index = 0; index < NUM_THREADS; ++index){
thread_args[index] = index;
printf("Creating thread %d\n", index);
result_code = pthread_create(&threads[index], NULL, perform_work(), (void *) &thread_args[index]);
assert(0 == result_code);
}
// wait for each thread to complete
for (index = 0; index < NUM_THREADS; ++index) {
// block until thread 'index' completes
result_code = pthread_join(threads[index], NULL);
printf("In main: thread %d has completed\n", index);
assert(0 == result_code);
}
printf("In main: all threads completed successfully\n");
//release a few processes
release_pid(303); printf("\nProcess 303 released.");
release_pid(308); printf("\nProcess 308 released.");
release_pid(309); printf("\nProcess 309 released.");
//allocate a few more processes after this release
int val = allocate_pid(); printf("\nProcess %d : pid = %d", ++i, val); //should be 303
val = allocate_pid(); printf("\nProcess %d : pid = %d\n", ++i, val); //should be 308
}
void *perform_work(void *argument){
map = allocate_map();
i = 0;
id = 0;
if (map == 1) {
printf("\nBitmap Data Structure initialized.\n");
int val = allocate_pid();
printf("\nProcess %d: pid = %d\n", i+1, val);
i++;
}
else printf("\nFailed to initialize data structure.\n");
}
/* Creates and initializes a bitmap data structure for representing pids;
returns —1 for unsuccessful, 1 for successful */
int allocate_map() {
unsignedChar = (unsigned char*)malloc((sz+CB-1)/CB * sizeof(char));
if (unsignedChar) return 1;
return -1;
}
/* Allocates and returns a pid; returns -1
if it is unable to allocate a pid (all pids are in use) */
int allocate_pid() {
int i = 0;
int pid = unsignedChar[i/CB] & (1 << (i & (CB-1)));
while (pid != 0) {
i++;
pid = unsignedChar[i/CB] & (1 << (i & (CB-1)));
}
if (i+MIN_PID > MAX_PID) return -1;
unsignedChar[i/CB] |= 1 << (i & (CB-1));
return i+MIN_PID;
}
/* Releases a pid given a pid parameter*/
void release_pid(int pid) {
if (pid < 300) {
printf("\nInvalid PID: It should lie between 300 and 3000.");
return;
}
int i = pid - MIN_PID;
unsignedChar[i/CB] &= ~(1 << (i & (CB-1)));
}
This has obviously been done before, but the trouble with this code is that it simply is not incrementing, but it is doing everything else fine. I want to have it where the output of the file reads the integer that the loop is going up to. Instead, it gets stuck at 0. I need some help. I am writing this in C. Here is my code:
assignment9.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include "tellwait.h"
void err_sys(const char* message);
int main(void){
FILE *filepoint;
int* zero = 0;
int val;
char* buffer[180];
pid_t pid;
filepoint = fopen("testfile.txt", "w+");
fprintf(filepoint, "%d", zero);
TELL_WAIT();
if((pid = fork()) < 0)
{
err_sys("fork error");
}
else if (pid == 0) //child
{
int i;
for(i = 0; i < 10; i++){
WAIT_PARENT();
filepoint = fopen("testfile.txt", "w+");
fread(buffer, sizeof(zero), 1, filepoint);
// increment
val = atoi(buffer[0]);
val++;
// use fprintf to write back to file
//printf("Current amount: %d, Child Process\n", zero);
printf("%d\n", val);
fprintf(filepoint, "%d", val);
TELL_PARENT(pid);
}
}
else { //parent
int i;
for(i = 0; i < 10; i++){
filepoint = fopen("testfile.txt", "w+");
fread(buffer, sizeof(zero), 1, filepoint);
// increment
val = atoi(buffer[0]);
val++;
// use fprintf to write back to file
//printf("Current amount: %d, Parent Process\n", zero);
printf("%d\n", val);
fprintf(filepoint, "%d", val);
TELL_CHILD(pid);
WAIT_CHILD();
}
}
return EXIT_SUCCESS;
}
void err_sys(const char* message)
{
printf("%s\n", message);
exit(0);
}
tellwait.h:
#ifndef _TELL_WAIT_H
#define _TELL_WAIT_H
void TELL_WAIT(void); /* parent/child from {Sec race_conditions} */
void TELL_PARENT(pid_t);
void TELL_CHILD(pid_t);
void WAIT_PARENT(void);
void WAIT_CHILD(void);
#endif
tellwait.c:
#include <stdlib.h>
#include <signal.h>
void err_sys (const char* message);
static volatile sig_atomic_t sigflag; /* set nonzero by sig handler */
static sigset_t newmask, oldmask, zeromask;
static void sig_usr(int signo) /* one signal handler for SIGUSR1 and SIGUSR2 */
{
sigflag = 1;
}
void TELL_WAIT(void)
{
if (signal(SIGUSR1, sig_usr) == SIG_ERR)
err_sys("signal(SIGUSR1) error");
if (signal(SIGUSR2, sig_usr) == SIG_ERR)
err_sys("signal(SIGUSR2) error");
sigemptyset(&zeromask);
sigemptyset(&newmask);
sigaddset(&newmask, SIGUSR1);
sigaddset(&newmask, SIGUSR2);
/* Block SIGUSR1 and SIGUSR2, and save current signal mask */
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
err_sys("SIG_BLOCK error");
}
void TELL_PARENT(pid_t pid)
{
kill(pid, SIGUSR2); /* tell parent we're done */
}
void WAIT_PARENT(void)
{
while (sigflag == 0)
sigsuspend(&zeromask); /* and wait for parent */
sigflag = 0;
/* Reset signal mask to original value */
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys("SIG_SETMASK error");
}
void TELL_CHILD(pid_t pid)
{
kill(pid, SIGUSR1); /* tell child we're done */
}
void WAIT_CHILD(void)
{
while (sigflag == 0)
sigsuspend(&zeromask); /* and wait for child */
sigflag = 0;
/* Reset signal mask to original value */
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys("SIG_SETMASK error");
}
The file output for testfile.txt is 10, while the test console output I am attempting to get is:
1
2
3
4
5
6
7
8
9
10
May you please help me?
This is my first post and I'm excited.
My problem is that I am creating a Rock, Paper, Scissors program in C where the parent process creates 2 threads. The 2 threads then throw a random rock, paper, or scissors and return the value to the parent where it gets counted and spits back the results of 3 rounds, then makes a final tally.
My problem is that I cannot get the threads to initiate correctly, I have them waiting in my thread_function1 but then they only complete one round and even then I don't get two threads back in the results. If someone could please shed some light I would really appreciate it! Thanks
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <sys/time.h>
#define NTHREADS 2
struct timeval tv;
void *thread_function1();
void *thread_function2();
char *guess_string(int g);
int wins[3];
int cmd_ready = 0;
int x1=0, x2=1, count=0;
int guess, object, turns, i, j, k,l, winner, cmd, go, y;
pthread_mutex_t cv_m;
pthread_mutex_t count_mutex;
pthread_cond_t cv;
int myindex;
int flag;
int throws[3];
int main(int argc, char *argv[])
{
wins[0] = 0; wins[1] = 0;
if ((argc != 2) || ((turns = atoi(argv[1])) <= 0))
{
fprintf(stderr,"Usage: %s turns\n", argv[0]);
return 0;
}
pthread_t thread_id1, thread_id2;
if (pthread_create(&thread_id1, NULL, thread_function1,&x1) != 0)
perror("pthread_create"),
exit(1);
if (pthread_create(&thread_id2, NULL, thread_function1,&x2) != 0)
perror("pthread_create"),
exit(1);
printf("Beginning %d Rounds...\nFight!\n", turns);
printf("Child 1 TID: %d\n", (unsigned int) thread_id1);
printf("Child 2 TID: %d\n", (unsigned int) thread_id2 );
for(k=0; k<turns; k++)
{
pthread_mutex_lock (&cv_m);
cmd = go;
cmd_ready = 2;
pthread_cond_broadcast(&cv);
pthread_mutex_unlock(&cv_m);
printf("------------------------\n");
printf("Round: %d\n", k+1);
printf("Child %d throws %s!\n",myindex+1, guess_string(myindex));
pthread_mutex_lock (&count_mutex);
winner = find_winner(throws[0], throws[1]);
while(count == 2){
if(winner >= 0)
{
printf("Child %d Wins!\n", winner+1);
wins[winner]++;
printf("6\n");
}else
{
printf("Game is a Tie!\n");
}
go--;
count = 0;
pthread_mutex_unlock(&count_mutex);
}
}
pthread_join(thread_id1,NULL);
pthread_join(thread_id2,NULL);
printf("------------------------\n");
printf("------------------------\n");
printf("Result:\n");
printf("Child 1: %d\n", wins[0]);
printf("Child 2: %d\n", wins[1]);
printf("Ties: %d\n", turns - (wins[0] + wins[1]));
printf("Child %d Wins!\n", (wins[0] > wins[1]) ? 1 : 2);
pthread_mutex_destroy(&cv_m);
pthread_cond_destroy(&cv);
pthread_exit(NULL);
return 0;
}
void *thread_function1(void *p)
{
struct timeval tv;
myindex = *(int *)p;
gettimeofday(&tv, NULL);
srand(tv.tv_sec + tv.tv_usec + getpid());
printf("1\n");
pthread_mutex_lock (&cv_m);
while(cmd_ready == 0)
{
printf("2\n");
pthread_cond_wait(&cv, &cv_m);
}
printf("3\n");
throws[myindex] = rand() % 3;
cmd_ready--;
printf("Ready: %d\n",cmd_ready);
pthread_mutex_unlock (&cv_m);
printf("4\n");
pthread_mutex_lock (&count_mutex);
count++;
printf("Count %d\n", count);
pthread_mutex_unlock(&count_mutex);
while(count == 2){
printf("5\n");
return NULL;
}
}
char *guess_string(int g){
switch(g){
case 0:
return "Rock";
break;
case 1:
return "Paper";
break;
case 2:
return "Scissors";
break;
}
}
int find_winner(int g1, int g2){
if(g1 == g2)
return -1;
else if ((g1 == 2) && (g2 == 0))
return 1;
else if ((g1 == 0) && (g2 == 2))
return 0;
else
return (g1 > g2) ? 0 : 1;
}
You don't appear to be initializing your mutex or condition with pthread_mutex_init or pthread_cond_init.
The variable myindex is being modified by both threads without protection, the second thread to update this variable will be the one that appears to report back.
You are also counting on your threads to begin pending on the condition before main grabs the lock and issues the broadcast, you could have a case where main gets there first and your threads won't be ready.
That should be a start.