Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
230
Task/Rendezvous/C/rendezvous-1.c
Normal file
230
Task/Rendezvous/C/rendezvous-1.c
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* The language task, implemented with pthreads for POSIX systems. */
|
||||
|
||||
/* Each rendezvous_t will be accepted by a single thread, and entered
|
||||
* by one or more threads. accept_func() only returns an integer and
|
||||
* is always run within the entering thread's context to simplify
|
||||
* handling the arguments and return value. This somewhat unlike an
|
||||
* Ada rendezvous and is a subset of the Ada rendezvous functionality.
|
||||
* Ada's in and out parameters can be simulated via the void pointer
|
||||
* passed to accept_func() to update variables owned by both the
|
||||
* entering and accepting threads, if a suitable struct with pointers
|
||||
* to those variables is used. */
|
||||
typedef struct rendezvous {
|
||||
pthread_mutex_t lock; /* A mutex/lock to use with the CVs. */
|
||||
pthread_cond_t cv_entering; /* Signaled when a thread enters. */
|
||||
pthread_cond_t cv_accepting; /* Signaled when accepting thread is ready. */
|
||||
pthread_cond_t cv_done; /* Signaled when accept_func() finishes. */
|
||||
int (*accept_func)(void*); /* The function to run when accepted. */
|
||||
int entering; /* Number of threads trying to enter. */
|
||||
int accepting; /* True if the accepting thread is ready. */
|
||||
int done; /* True if accept_func() is done. */
|
||||
} rendezvous_t;
|
||||
|
||||
/* Static initialization for rendezvous_t. */
|
||||
#define RENDEZVOUS_INITILIZER(accept_function) { \
|
||||
.lock = PTHREAD_MUTEX_INITIALIZER, \
|
||||
.cv_entering = PTHREAD_COND_INITIALIZER, \
|
||||
.cv_accepting = PTHREAD_COND_INITIALIZER, \
|
||||
.cv_done = PTHREAD_COND_INITIALIZER, \
|
||||
.accept_func = accept_function, \
|
||||
.entering = 0, \
|
||||
.accepting = 0, \
|
||||
.done = 0, \
|
||||
}
|
||||
|
||||
int enter_rendezvous(rendezvous_t *rv, void* data)
|
||||
{
|
||||
/* Arguments are passed in and out of the rendezvous via
|
||||
* (void*)data, and the accept_func() return value is copied and
|
||||
* returned to the caller (entering thread). A data struct with
|
||||
* pointers to variables in both the entering and accepting
|
||||
* threads can be used to simulate Ada's in and out parameters, if
|
||||
* needed. */
|
||||
pthread_mutex_lock(&rv->lock);
|
||||
|
||||
rv->entering++;
|
||||
pthread_cond_signal(&rv->cv_entering);
|
||||
|
||||
while (!rv->accepting) {
|
||||
/* Nothing is accepting yet, keep waiting. pthreads will
|
||||
* queue all waiting entries. The loop is needed to handle
|
||||
* both race conditions and spurious wakeups. */
|
||||
pthread_cond_wait(&rv->cv_accepting, &rv->lock);
|
||||
}
|
||||
|
||||
/* Call accept_func() and copy the return value before leaving
|
||||
* the mutex. */
|
||||
int ret = rv->accept_func(data);
|
||||
|
||||
/* This signal is needed so that the accepting thread will wait
|
||||
* for the rendezvous to finish before trying to accept again. */
|
||||
rv->done = 1;
|
||||
pthread_cond_signal(&rv->cv_done);
|
||||
|
||||
rv->entering--;
|
||||
rv->accepting = 0;
|
||||
pthread_mutex_unlock(&rv->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void accept_rendezvous(rendezvous_t *rv)
|
||||
{
|
||||
/* This accept function does not take in or return parameters.
|
||||
* That is handled on the entry side. This is only for
|
||||
* synchronization. */
|
||||
pthread_mutex_lock(&rv->lock);
|
||||
rv->accepting = 1;
|
||||
|
||||
while (!rv->entering) {
|
||||
/* Nothing to accept yet, keep waiting. */
|
||||
pthread_cond_wait(&rv->cv_entering, &rv->lock);
|
||||
}
|
||||
|
||||
pthread_cond_signal(&rv->cv_accepting);
|
||||
|
||||
while (!rv->done) {
|
||||
/* Wait for accept_func() to finish. */
|
||||
pthread_cond_wait(&rv->cv_done, &rv->lock);
|
||||
}
|
||||
rv->done = 0;
|
||||
|
||||
rv->accepting = 0;
|
||||
pthread_mutex_unlock(&rv->lock);
|
||||
}
|
||||
|
||||
/* The printer use case task implemented using the above rendezvous
|
||||
* implementation. Since C doesn't have exceptions, return values are
|
||||
* used to signal out of ink errors. */
|
||||
|
||||
typedef struct printer {
|
||||
rendezvous_t rv;
|
||||
struct printer *backup;
|
||||
int id;
|
||||
int remaining_lines;
|
||||
} printer_t;
|
||||
|
||||
typedef struct print_args {
|
||||
struct printer *printer;
|
||||
const char* line;
|
||||
} print_args_t;
|
||||
|
||||
int print_line(printer_t *printer, const char* line) {
|
||||
print_args_t args;
|
||||
args.printer = printer;
|
||||
args.line = line;
|
||||
return enter_rendezvous(&printer->rv, &args);
|
||||
}
|
||||
|
||||
int accept_print(void* data) {
|
||||
/* This is called within the rendezvous, so everything is locked
|
||||
* and okay to modify. */
|
||||
print_args_t *args = (print_args_t*)data;
|
||||
printer_t *printer = args->printer;
|
||||
const char* line = args->line;
|
||||
|
||||
if (printer->remaining_lines) {
|
||||
/* Print the line, character by character. */
|
||||
printf("%d: ", printer->id);
|
||||
while (*line != '\0') {
|
||||
putchar(*line++);
|
||||
}
|
||||
putchar('\n');
|
||||
printer->remaining_lines--;
|
||||
return 1;
|
||||
}
|
||||
else if (printer->backup) {
|
||||
/* "Requeue" this rendezvous with the backup printer. */
|
||||
return print_line(printer->backup, line);
|
||||
}
|
||||
else {
|
||||
/* Out of ink, and no backup available. */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
printer_t backup_printer = {
|
||||
.rv = RENDEZVOUS_INITILIZER(accept_print),
|
||||
.backup = NULL,
|
||||
.id = 2,
|
||||
.remaining_lines = 5,
|
||||
};
|
||||
|
||||
printer_t main_printer = {
|
||||
.rv = RENDEZVOUS_INITILIZER(accept_print),
|
||||
.backup = &backup_printer,
|
||||
.id = 1,
|
||||
.remaining_lines = 5,
|
||||
};
|
||||
|
||||
void* printer_thread(void* thread_data) {
|
||||
printer_t *printer = (printer_t*) thread_data;
|
||||
while (1) {
|
||||
accept_rendezvous(&printer->rv);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct poem {
|
||||
char* name;
|
||||
char* lines[];
|
||||
} poem_t;
|
||||
|
||||
poem_t humpty_dumpty = {
|
||||
.name = "Humpty Dumpty",
|
||||
.lines = {
|
||||
"Humpty Dumpty sat on a wall.",
|
||||
"Humpty Dumpty had a great fall.",
|
||||
"All the king's horses and all the king's men",
|
||||
"Couldn't put Humpty together again.",
|
||||
""
|
||||
},
|
||||
};
|
||||
|
||||
poem_t mother_goose = {
|
||||
.name = "Mother Goose",
|
||||
.lines = {
|
||||
"Old Mother Goose",
|
||||
"When she wanted to wander,",
|
||||
"Would ride through the air",
|
||||
"On a very fine gander.",
|
||||
"Jack's mother came in,",
|
||||
"And caught the goose soon,",
|
||||
"And mounting its back,",
|
||||
"Flew up to the moon.",
|
||||
""
|
||||
},
|
||||
};
|
||||
|
||||
void* poem_thread(void* thread_data) {
|
||||
poem_t *poem = (poem_t*)thread_data;
|
||||
|
||||
for (unsigned i = 0; poem->lines[i] != ""; i++) {
|
||||
int ret = print_line(&main_printer, poem->lines[i]);
|
||||
if (ret < 0) {
|
||||
printf(" %s out of ink!\n", poem->name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
pthread_t threads[4];
|
||||
|
||||
pthread_create(&threads[0], NULL, poem_thread, &humpty_dumpty);
|
||||
pthread_create(&threads[1], NULL, poem_thread, &mother_goose);
|
||||
pthread_create(&threads[2], NULL, printer_thread, &main_printer);
|
||||
pthread_create(&threads[3], NULL, printer_thread, &backup_printer);
|
||||
|
||||
pthread_join(threads[0], NULL);
|
||||
pthread_join(threads[1], NULL);
|
||||
pthread_cancel(threads[2]);
|
||||
pthread_cancel(threads[3]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
72
Task/Rendezvous/C/rendezvous-2.c
Normal file
72
Task/Rendezvous/C/rendezvous-2.c
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <omp.h>
|
||||
|
||||
typedef struct printer printer;
|
||||
struct printer { int id, ink; };
|
||||
printer pnt_main = { 1, 5 };
|
||||
printer pnt_backup = { 2, 5 };
|
||||
|
||||
int print(const char * text, const char **error)
|
||||
{
|
||||
#pragma omp critical
|
||||
{
|
||||
printer *p = &pnt_main;
|
||||
if (!p->ink) p = &pnt_backup;
|
||||
if (!p->ink)
|
||||
*error = "Out of ink";
|
||||
else {
|
||||
*error = 0;
|
||||
p->ink--;
|
||||
printf("%d | ", p->id, p->ink);
|
||||
while (*text != '\0') {
|
||||
putchar(*(text++));
|
||||
fflush(stdout);
|
||||
usleep(30000);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
return 0 != *error;
|
||||
}
|
||||
|
||||
const char *humpty[] = {
|
||||
"Humpty Dumpty sat on a wall.",
|
||||
"Humpty Dumpty had a great fall.",
|
||||
"All the king's horses and all the king's men,",
|
||||
"Couldn't put Humpty together again."
|
||||
};
|
||||
|
||||
const char *goose[] = {
|
||||
"Old Mother Goose,",
|
||||
"When she wanted to wander,",
|
||||
"Would ride through the air,",
|
||||
"On a very fine gander.",
|
||||
"Jack's mother came in,",
|
||||
"And caught the goose soon,",
|
||||
"And mounting its back,",
|
||||
"Flew up to the moon."
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
int i, j, len;
|
||||
const char *msg, **text;
|
||||
|
||||
omp_set_num_threads(2);
|
||||
|
||||
#pragma omp parallel for private(text, msg, len, j)
|
||||
for (i = 0; i < 2; i++) {
|
||||
text = i ? goose : humpty;
|
||||
len = (i ? sizeof(goose) : sizeof(humpty) ) / sizeof(const char*);
|
||||
for (j = 0; j < len; j++) {
|
||||
usleep(100000);
|
||||
if (print(text[j], &msg)) {
|
||||
fprintf(stderr, "Error: %s\n", msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue