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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include /*semaphore*/
#include /*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;
}