From: Gustavo Martin Morcuende Date: Sun, 5 Jun 2016 19:38:18 +0000 (+0200) Subject: flocks.c: testing thread concurrency X-Git-Url: https://git.gumartinm.name/?a=commitdiff_plain;h=3ea6793ad3862e7d33099166e5db676ed3bed5dd;p=CForFun.git flocks.c: testing thread concurrency --- diff --git a/locks/Makefile b/locks/Makefile index 0a216ce..9a14c0d 100644 --- a/locks/Makefile +++ b/locks/Makefile @@ -1,7 +1,7 @@ -all: locks +all: flocks -locks: locks.c - gcc -Wall -g -o locks locks.c -lpthread +flocks: flocks.c + gcc -Wall -g -o flocks flocks.c -lpthread clean: - rm -f locks + rm -f flocks diff --git a/locks/flocks.c b/locks/flocks.c new file mode 100644 index 0000000..df55583 --- /dev/null +++ b/locks/flocks.c @@ -0,0 +1,311 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "flocks.h" + + + +pthread_mutex_t gateMutex; +pthread_cond_t gateBroadCast; +bool isGateOpen = false; +int threadsNumber = 20; + + +struct sigaction sigintAction; /*Stores the init SIGINT sigaction value*/ +char *fileName = "/tmp/locks"; + + + + + + +int main (int argc, char *argv[]) +{ + int c; /*Getopt parameter*/ + /*Default values*/ + struct sigaction sa; /*sig actions values*/ + + opterr = 0; + while ((c = getopt (argc, argv, "p:t:f:")) != -1) { + switch (c) { + case 'p': + fileName = optarg; + break; + case 't': + threadsNumber = atoi(optarg); + break; + case '?': + if ((optopt == 'p') || (optopt == 't') || (optopt == 'f')) + fprintf (stderr, "Option -%c requires an argument.\n", optopt); + else if (isprint (optopt)) + fprintf (stderr, "Invalid option '-%c'.\n", optopt); + else + fprintf (stderr, "Unknown option character '\\x%x'.\n", optopt); + return -1; + default: + abort (); + } + } + + /*This program does not admit options*/ + if (optind < argc) { + fprintf (stderr, "This program does not admit options just argument elements with their values.\n"); + return -1; + } + + + /* If running from console, user may finish this process using SIGINT (Ctrl-C)*/ + /* Check to make sure that the shell has not set up an initial action of SIG_IGN before I establish my own signal handler. + * As seen on http://www.gnu.org/software/libc/manual/html_node/Initial-Signal-Actions.html#Initial-Signal-Actions + */ + memset (&sa, 0, sizeof(sa)); + memset (&sigintAction, 0, sizeof(sigaction)); + if (sigaction (SIGINT, NULL, &sa) < 0) { + fprintf (stderr, "%s: %s\n", "SIGINT retrieve current signal handler failed:", strerror(errno)); + + return -1; + } + + if (sa.sa_handler != SIG_IGN) { + /* Save the current SIGINT sigaction value. We use it to restore SIGINT handler in my custom SIGINT handler.*/ + memcpy (&sigintAction, &sa, sizeof(sigaction)); + + sa.sa_handler = &sigint_handler; + sa.sa_flags = SA_RESTART; + if (sigemptyset(&sa.sa_mask) < 0) { + fprintf (stderr, "%s: %s\n", "SIGINT empty mask", strerror(errno)); + + return -1; + } + if (sigaction(SIGINT, &sa, NULL) < 0) { + fprintf (stderr, "%s: %s\n", "SIGINT set signal handler failed", strerror(errno)); + + return -1; + } + } + + if (threadsNumber > 0) { + return test_threads_concurrency(); + } else { + return test_require_user(); + } + + return 0; +} + +int test_threads_concurrency() +{ + int returnValue = 0; + int createIndex; + int joinIndex; + pthread_t threadIds [threadsNumber]; /*Threads identifier numbers*/ + + pthread_mutex_init(&gateMutex, NULL); + pthread_cond_init(&gateBroadCast, NULL); + closeGate(); + + + for (createIndex = 0; createIndex < threadsNumber; createIndex++) { + print_with_date (stdout, "Thread %d created\n", createIndex); + if (pthread_create (&threadIds[createIndex], NULL, &thread_lock, (void *) createIndex) != 0 ) { + print_with_date (stderr, "Thread %d creation failed\n", createIndex, strerror(errno)); + returnValue = -1; + break; + } + } + + sleep(5); + openGate(); + + for (joinIndex = createIndex; joinIndex --> 0; ) { + if (pthread_join(threadIds[joinIndex], NULL) != 0) { + print_with_date (stderr, "Thread %d join error\n", joinIndex, strerror(errno)); + returnValue = -1; + } + } + + return returnValue; +} + +void *thread_lock(void * arg) +{ + int threadNumber; + int fd; + int flockErr; + + threadNumber = (int) arg; + + + fd = open(fileName, O_CREAT | O_RDWR, 0664); + if (fd == -1) { + goto end; + print_with_date (stderr, "Thread %d, open file error", threadNumber, strerror(errno)); + } + + + gate(); + + + print_with_date (stdout, "Thread %d: before lock\n", threadNumber); + do { + flockErr = flock(fd, LOCK_EX); + } while(flockErr == -1 && errno == EINTR); + + if (flockErr == -1) { + print_with_date (stderr, "Thread %d: flock get exclusive lock error", threadNumber, strerror(errno)); + goto end; + } + print_with_date (stdout, "Thread %d: after lock\n", threadNumber); + + + sleep(5); + + + print_with_date(stdout, "Thread %d: before release lock\n", threadNumber); + do { + flockErr = flock(fd, LOCK_UN); + } while(flockErr == -1 && errno == EINTR); + + if (flockErr == -1) { + print_with_date(stderr, "Thread %d: flock unlock error", threadNumber, strerror(errno)); + goto end; + } + print_with_date(stdout, "Thread %d: after release lock\n", threadNumber); + + +end: + close (fd); + pthread_exit(0); +} + +int test_require_user() { + int returnValue = -1; + int fd; + int flockErr; + + + fd = open(fileName, O_CREAT | O_RDWR, 0664); + if (fd == -1) { + print_with_date(stderr, "Open file error", strerror(errno)); + goto end; + } + + + fprintf(stdout, "Press ENTER key for locking file: %s\n", fileName); + fflush(stdout); + getchar(); + + + print_with_date(stdout, "Before lock\n"); + do { + flockErr = flock(fd, LOCK_EX); + } while(flockErr == -1 && errno == EINTR); + + if (flockErr == -1) { + print_with_date (stderr, "flock get exclusive lock error", strerror(errno)); + goto end; + } + print_with_date(stdout, "After lock\n"); + + + fprintf(stdout, "Press ENTER key for unlocking file: %s\n", fileName); + fflush(stdout); + getchar(); + + + print_with_date(stdout, "Before release lock\n"); + do { + flockErr = flock(fd, LOCK_UN); + } while(flockErr == -1 && errno == EINTR); + + if (flockErr == -1) { + print_with_date (stderr, "flock unlock error", strerror(errno)); + goto end; + } + print_with_date (stdout, "After release lock\n"); + + + returnValue = 0; +end: + close (fd); + return returnValue; +} + +int print_with_date(FILE *stream, const char *format, ...) { + va_list arg; + int done; + time_t rawtime; + char buff[100]; + char msg[50]; + char dateformatter[100] = "%s: "; + struct tm timeinfo; + + time ( &rawtime); + localtime_r ( &rawtime, &timeinfo); + strftime(buff, 50, "%Y-%m-%d %H:%M:%S", &timeinfo); + + va_start (arg, format); + vsnprintf (msg , 50, format, arg); + + strcat(dateformatter, msg); + done = fprintf (stream, dateformatter, buff, msg); + va_end (arg); + + if (done < 0) { + fflush (stream); + return done; + } else { + done = fflush (stream); + return done; + } +} + +void gate() { + + pthread_mutex_lock(&gateMutex); + + while(!isGateOpen) { + pthread_cond_wait(&gateBroadCast, &gateMutex); + } + + pthread_mutex_unlock(&gateMutex); +} + +void openGate() { + pthread_mutex_lock(&gateMutex); + + isGateOpen = true; + pthread_cond_broadcast(&gateBroadCast); + + pthread_mutex_unlock(&gateMutex); +} + +void closeGate() { + pthread_mutex_lock(&gateMutex); + + isGateOpen = false; + + pthread_mutex_unlock(&gateMutex); +} + +void sigint_handler(int sig) +{ + if (sigaction(SIGINT, &sigintAction, NULL) < 0) { + exit (EXIT_FAILURE); + } + kill(getpid(), SIGINT); +} + + diff --git a/locks/flocks.h b/locks/flocks.h new file mode 100644 index 0000000..7535209 --- /dev/null +++ b/locks/flocks.h @@ -0,0 +1,37 @@ + + + +void gate(); + +void openGate(); + +void closeGate(); + +int print_with_date(FILE *stream, const char *format, ...); + +/****************************************************************************************/ +/* This method is used by pthread_create */ +/* */ +/* INPUT PARAMETER: socket file descriptor */ +/* RETURNS: void */ +/****************************************************************************************/ +void *thread_lock(void *arg); + + +int test_threads_concurrency(); + +int test_require_user(); + + + + +/****************************************************************************************/ +/* This method is used by pthread_create */ +/* */ +/* INPUT PARAMETER: socket file descriptor */ +/* RETURNS: void */ +/****************************************************************************************/ +void sigint_handler(); + + + diff --git a/locks/locks.c b/locks/locks.c deleted file mode 100644 index 681c2f7..0000000 --- a/locks/locks.c +++ /dev/null @@ -1,241 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "locks.h" - - - -pthread_mutex_t gateMutex; -pthread_cond_t gateBroadCast; -bool isGateOpen = false; -int threadsNumber = 20; - - -struct sigaction sigintAction; /*Stores the init SIGINT sigaction value*/ -char *fileName = "/tmp/locks"; - - - - - - -int main (int argc, char *argv[]) -{ - int c; /*Getopt parameter*/ - /*Default values*/ - struct sigaction sa; /*sig actions values*/ - - opterr = 0; - while ((c = getopt (argc, argv, "p:t:f:")) != -1) { - switch (c) { - case 'p': - fileName = optarg; - break; - case 't': - threadsNumber = atoi(optarg); - break; - case '?': - if ((optopt == 'p') || (optopt == 't') || (optopt == 'f')) - fprintf (stderr, "Option -%c requires an argument.\n", optopt); - else if (isprint (optopt)) - fprintf (stderr, "Invalid option '-%c'.\n", optopt); - else - fprintf (stderr, "Unknown option character '\\x%x'.\n", optopt); - return -1; - default: - abort (); - } - } - - /*This program does not admit options*/ - if (optind < argc) { - fprintf (stderr, "This program does not admit options just argument elements with their values.\n"); - return -1; - } - - - /* If running from console, user may finish this process using SIGINT (Ctrl-C)*/ - /* Check to make sure that the shell has not set up an initial action of SIG_IGN before I establish my own signal handler. - * As seen on http://www.gnu.org/software/libc/manual/html_node/Initial-Signal-Actions.html#Initial-Signal-Actions - */ - memset (&sa, 0, sizeof(sa)); - memset (&sigintAction, 0, sizeof(sigaction)); - if (sigaction (SIGINT, NULL, &sa) < 0) { - fprintf (stderr, "%s: %s\n", "SIGINT retrieve current signal handler failed:", strerror(errno)); - - return -1; - } - - if (sa.sa_handler != SIG_IGN) { - /* Save the current SIGINT sigaction value. We use it to restore SIGINT handler in my custom SIGINT handler.*/ - memcpy (&sigintAction, &sa, sizeof(sigaction)); - - sa.sa_handler = &sigint_handler; - sa.sa_flags = SA_RESTART; - if (sigemptyset(&sa.sa_mask) < 0) { - fprintf (stderr, "%s: %s\n", "SIGINT empty mask", strerror(errno)); - - return -1; - } - if (sigaction(SIGINT, &sa, NULL) < 0) { - fprintf (stderr, "%s: %s\n", "SIGINT set signal handler failed", strerror(errno)); - - return -1; - } - } - - - if (main_process () < 0) - return -1; - - return 0; -} - -int main_process () -{ - int createIndex; - int joinIndex; - pthread_t threadIds [threadsNumber]; /*Threads identifier numbers*/ - - pthread_mutex_init(&gateMutex, NULL); - pthread_cond_init(&gateBroadCast, NULL); - closeGate(); - - - for (createIndex = 0; createIndex < threadsNumber; createIndex++) { - print_with_date (stdout, "Thread %d created\n", createIndex); - if (pthread_create (&threadIds[createIndex], NULL, &thread_lock, (void *) createIndex) != 0 ) { - print_with_date (stderr, "Thread %d creation failed\n", createIndex, strerror(errno)); - break; - } - } - - sleep(5); - openGate(); - - for (joinIndex = createIndex; joinIndex --> 0; ) { - if (pthread_join(threadIds[joinIndex], NULL) != 0) { - print_with_date (stderr, "Thread %d join error\n", joinIndex, strerror(errno)); - } - } - - return 0; -} - -void *thread_lock(void * arg) { - int threadNumber; - int fd; - int flockErr; - - threadNumber = (int) arg; - - fd = open(fileName, O_CREAT | O_RDWR, 0664); - if (fd == -1) { - print_with_date (stderr, "Thread %d, open file error", threadNumber, strerror(errno)); - } - - gate(); - - print_with_date (stdout, "Thread %d: before lock\n", threadNumber); - do { - flockErr = flock(fd, LOCK_EX); - } while(flockErr == -1 && errno == EINTR); - - - if (flockErr == -1) { - print_with_date (stderr, "Thread %d: flock error", threadNumber, strerror(errno)); - } - print_with_date (stdout, "Thread %d: after lock\n", threadNumber); - - sleep(5); - - print_with_date (stdout, "Thread %d: before release lock\n", threadNumber); - do { - flockErr = flock(fd, LOCK_UN); - } while(flockErr == -1 && errno == EINTR); - print_with_date (stdout, "Thread %d: after release lock\n", threadNumber); - - close (fd); - - pthread_exit(0); -} - -int print_with_date(FILE *stream, const char *format, ...) -{ - va_list arg; - int done; - time_t rawtime; - char buff[100]; - char msg[50]; - char dateformatter[100] = "%s: "; - struct tm timeinfo; - - time ( &rawtime); - localtime_r ( &rawtime, &timeinfo); - strftime(buff, 50, "%Y-%m-%d %H:%M:%S", &timeinfo); - - va_start (arg, format); - vsnprintf (msg , 50, format, arg); - - strcat(dateformatter, msg); - done = fprintf (stream, dateformatter, buff, msg); - va_end (arg); - - if (done < 0) { - fflush (stream); - return done; - } else { - done = fflush (stream); - return done; - } -} - -void gate() { - - pthread_mutex_lock(&gateMutex); - - while(!isGateOpen) { - pthread_cond_wait(&gateBroadCast, &gateMutex); - } - - pthread_mutex_unlock(&gateMutex); -} - -void openGate() { - pthread_mutex_lock(&gateMutex); - - isGateOpen = true; - pthread_cond_broadcast(&gateBroadCast); - - pthread_mutex_unlock(&gateMutex); -} - -void closeGate() { - pthread_mutex_lock(&gateMutex); - - isGateOpen = false; - - pthread_mutex_unlock(&gateMutex); -} - -void sigint_handler(int sig) -{ - if (sigaction(SIGINT, &sigintAction, NULL) < 0) { - exit (EXIT_FAILURE); - } - kill(getpid(), SIGINT); -} - - diff --git a/locks/locks.h b/locks/locks.h deleted file mode 100644 index 7fcdb4a..0000000 --- a/locks/locks.h +++ /dev/null @@ -1,41 +0,0 @@ - - - -void gate(); - -void openGate(); - -void closeGate(); - -int print_with_date(FILE *stream, const char *format, ...); - -/****************************************************************************************/ -/* This method is used by pthread_create */ -/* */ -/* INPUT PARAMETER: socket file descriptor */ -/* RETURNS: void */ -/****************************************************************************************/ -void *thread_lock (void *arg); - - -/****************************************************************************************/ -/* This method is used by pthread_create */ -/* */ -/* INPUT PARAMETER: socket file descriptor */ -/* RETURNS: int */ -/****************************************************************************************/ -int main_process (); - - - - -/****************************************************************************************/ -/* This method is used by pthread_create */ -/* */ -/* INPUT PARAMETER: socket file descriptor */ -/* RETURNS: void */ -/****************************************************************************************/ -void sigint_handler(); - - -