Threads and Semaphores in Linux

Threads and Semaphores in Linux

Semaphore Threads Assignment

Same as process assignment using threads instead of processes.

Sets up deadlock conditions for practice detecting and recovering.

Submit your .c source files and make file if needed

Two semaphores needed screen, keyboard

Use NAMED or Unamed semaphores.

Please see: http://man7.org/linux/man-pages/man7/sem_overview.7.htmland at least look at the major paragraphs

“Named semaphores”

and

“Unnamed semaphores (memory-based semaphores)”

The text below is called an algorithm, English description or design for code.  If you make this into comments you can put your code under each line which is how designs work.

mother process called ‘main’

sem_open both semaphores

Span 9 threads

Each thread passed index of loop so 1,2,3, or 4

Below is real C to show just how easy this is, please do not overthink

after all die

sem_unlink both

End Mother process

each thread

sem_open both semaphores if necessary

count = 0

loop

count += getSemaphores(index)

prompt “enter < 80 characters or q to quit: ”

readkeboard

echo

sem_post or give back both semaphores

until quit end inner loop in C do … while not q

count += getSemaphores(index)

prompt “This thread” + threadid + “had ” + count + ” deadlocks ”

sem_post or give back both semaphores

sem_close

exit

function to get semaphores (index)

returns count of how many times recovered from deadlock

odd index gets screen first

even index gets keyboard first

count = 0

loop

sem_wait for first

sem_timedwait with timer for second

if timeout

give back first, (sem_post)

wait random time

increment count

else

have both  true

until have both

return count

end get semaphores function

 Solution

/*

* main.c

*

*/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <time.h>

#include <unistd.h>

#include <errno.h>

#include <fcntl.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <sys/wait.h>

#include <semaphore.h> /*semaphore*/

#include <pthread.h> /*pthread*/

/*Prototypes*/

void *processThread(void* threadId);

intgetSemaphores(intidx);

/*Macros*/

#define MAXBUFFER 80

#define KEYBSEM “/keybrd”

#define SCRNSEM “/screen”

#define MAX_THREAD_NUM 9

sem_t * semScrn;

sem_t * semKey;

/*

* Creates named semaphores, then forks 9 processes that call process, and finally waits

* for the children processes to die before unlinking the semaphores and exiting.

*/

int main(intargc, char const *argv[])

{

pthread_ttid[MAX_THREAD_NUM];

int index[MAX_THREAD_NUM];

int i = 0;

/*Open the semaphore used by processes*/

sem_unlink(SCRNSEM); //unlink if already there

sem_unlink(KEYBSEM);

if ((semScrn = sem_open(SCRNSEM, O_CREAT, S_IRGRP | S_IWGRP, 1)) == SEM_FAILED)

{

perror(“sem_open1”);

exit(0);

}

if ((semKey = sem_open(KEYBSEM, O_CREAT, S_IRGRP | S_IWGRP, 1)) == SEM_FAILED)

{

perror(“sem_open2”);

exit(0);

}

/*fork children processes with indices*/

for (i = 0; i < MAX_THREAD_NUM; i++)

{

index[i] = i + 1;

intcreateThread = pthread_create(&tid[i], NULL, processThread, (void*) &index[i]);

if (createThread< 0)

{

charmessage_print[100];

sprintf(message_print, “Create thread failed for thread id: %d”, i);

perror(message_print);

}

fprintf(stdout, “>> Create thread %d success.\n”, i + 1);

}

/* Waiting for threads to complete */

for (i = 0; i < MAX_THREAD_NUM; i++)

{

if (pthread_join(tid[i], NULL))

{

charmessage_print[100];

sprintf(message_print, “Error joining thread %d”, i + 1);

perror(message_print);

}

}

sem_unlink(SCRNSEM);

sem_unlink(KEYBSEM);

return 0;

}

/*

* Locks the two semaphores (screen and keybrd) with deadlock checking and resolution,

* and returns the number of deadlock incountered.

*/

intgetSemaphores(intidx)

{

int deadlocks = 0;

intgotBoth = 0;

int r = 0;

structtimespects;

while (gotBoth == 0)

{

if (clock_gettime(CLOCK_REALTIME, &ts) == -1)

{

perror(“clock_gettime”);

}

ts.tv_sec += 1;

if (idx % 2 == 0)

{ //even index gets keyboard first

sem_wait(semKey);

sleep(1);

r = sem_timedwait(semScrn, &ts);

} else

{ //odd index gets screen first

sem_wait(semScrn);

sleep(1);

r = sem_timedwait(semKey, &ts);

}

if (r == -1)

{

//fprintf(stderr, “got a deadlock!\n”);

if (errno == ETIMEDOUT)

{

//deadlock, give back and wait rand time

if (idx % 2 == 0)

{

if (sem_post(semKey) == -1)

{

perror(“sem_post”);

}

} else

{

if (sem_post(semScrn) == -1)

{

perror(“sem_post”);

}

}

} else

perror(“sem_timedwait”);

deadlocks++;

sleep(rand() % 3);

} else

gotBoth = 1;

}

return deadlocks;

}

/*

* Uses getSemaphores() to lock the required semaphores, and then echos input until

* a ‘q’ is read. The function exits at the end (kills child once it has echoed

* enough times rather than returning to the fork loop). Before it exits, it

* posts and closes used semaphores.

*/

void* processThread(void* threadId)

{

intidx = *((int*) threadId);

fprintf(stdout, “>> Thread %d start ……\n”, idx);

srand(time(NULL));

int count = 0;

char buffer[MAXBUFFER];

if ((semScrn = sem_open(SCRNSEM, O_CREAT, S_IRGRP | S_IWGRP, 1)) == SEM_FAILED)

{

perror(“sem_open1”);

return NULL;

}

if ((semKey = sem_open(KEYBSEM, O_CREAT, S_IRGRP | S_IWGRP, 1)) == SEM_FAILED)

{

perror(“sem_open2”);

return NULL;

}

do

{

count += getSemaphores(idx);

fprintf(stdout, “>> Thread %d. Enter < %d characters or q to quit\n”, idx, MAXBUFFER);

fprintf(stdout, “>> “);

if (!fgets(buffer, MAXBUFFER, stdin))

{

if (sem_post(semScrn) == -1 || sem_post(semKey) == -1)

{

perror(“sme_post”);

}

break;

}

fprintf(stdout, “>> Echo: %s”, buffer);

if (sem_post(semScrn) == -1 || sem_post(semKey) == -1)

{

perror(“sme_post”);

}

} while (strncmp(buffer, “q”, 1) != 0);

count += getSemaphores(idx);

fprintf(stdout, “>> This is thread %d: Had %d deadlocks\n”, idx, count);

if (sem_post(semScrn) == -1 || sem_post(semKey) == -1)

{

perror(“sme_post”);

}

if (sem_close(semScrn) == -1 || sem_close(semKey) == -1)

{

perror(“sme_close”);

}

return NULL;

}