mirror of https://github.com/t1meshift/os_labs.git
140 lines
2.9 KiB
C
140 lines
2.9 KiB
C
|
|
||
|
vector_t v[2 * MAX_THREADS];
|
||
|
|
||
|
// used to ensure print outs make sense
|
||
|
pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;
|
||
|
|
||
|
void usage(char *prog) {
|
||
|
fprintf(stderr, "usage: %s [-d (turn on deadlocking behavior)] [-l loops] [-n num_threads] [-t (do timing)] [-v (for verbose)]\n", prog);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
// only called by one thread (not thread-safe)
|
||
|
void vector_init(vector_t *v, int value) {
|
||
|
int i;
|
||
|
for (i = 0; i < VECTOR_SIZE; i++) {
|
||
|
v->values[i] = value;
|
||
|
}
|
||
|
Pthread_mutex_init(&v->lock, NULL);
|
||
|
}
|
||
|
|
||
|
// only called by one thread (not thread-safe)
|
||
|
void vector_print(vector_t *v, char *str) {
|
||
|
int i;
|
||
|
for (i = 0; i < VECTOR_SIZE; i++) {
|
||
|
printf("%s[%d] %d\n", str, i, v->values[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void print_info(int call_return, int thread_id, int v0, int v1) {
|
||
|
if (verbose == 0)
|
||
|
return;
|
||
|
Pthread_mutex_lock(&print_lock);
|
||
|
int j;
|
||
|
for (j = 0; j < thread_id; j++) printf(" ");
|
||
|
if (call_return)
|
||
|
printf("<-add(%d, %d)\n", v0, v1);
|
||
|
else
|
||
|
printf("->add(%d, %d)\n", v0, v1);
|
||
|
Pthread_mutex_unlock(&print_lock);
|
||
|
}
|
||
|
|
||
|
typedef struct __thread_arg_t {
|
||
|
int tid;
|
||
|
int vector_add_order;
|
||
|
int vector_0;
|
||
|
int vector_1;
|
||
|
} thread_arg_t;
|
||
|
|
||
|
void *worker(void *arg) {
|
||
|
thread_arg_t *args = (thread_arg_t *) arg;
|
||
|
int i, v0, v1;
|
||
|
for (i = 0; i < loops; i++) {
|
||
|
if (args->vector_add_order == 0) {
|
||
|
v0 = args->vector_0;
|
||
|
v1 = args->vector_1;
|
||
|
} else {
|
||
|
v0 = args->vector_1;
|
||
|
v1 = args->vector_0;
|
||
|
}
|
||
|
|
||
|
print_info(0, args->tid, v0, v1);
|
||
|
|
||
|
vector_add(&v[v0], &v[v1]);
|
||
|
|
||
|
print_info(1, args->tid, v0, v1);
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[]) {
|
||
|
opterr = 0;
|
||
|
int c;
|
||
|
while ((c = getopt (argc, argv, "l:n:vtdp")) != -1) {
|
||
|
switch (c) {
|
||
|
case 'l':
|
||
|
loops = atoi(optarg);
|
||
|
break;
|
||
|
case 'n':
|
||
|
num_threads = atoi(optarg);
|
||
|
break;
|
||
|
case 'v':
|
||
|
verbose = 1;
|
||
|
break;
|
||
|
case 't':
|
||
|
do_timing = 1;
|
||
|
break;
|
||
|
case 'd':
|
||
|
cause_deadlock = 1;
|
||
|
break;
|
||
|
case 'p':
|
||
|
enable_parallelism = 1;
|
||
|
break;
|
||
|
default:
|
||
|
usage(argv[0]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
assert(num_threads < MAX_THREADS);
|
||
|
|
||
|
pthread_t pid[MAX_THREADS];
|
||
|
thread_arg_t args[MAX_THREADS];
|
||
|
int i;
|
||
|
for (i = 0; i < num_threads; i++) {
|
||
|
args[i].tid = i;
|
||
|
if (enable_parallelism == 0) {
|
||
|
args[i].vector_0 = 0;
|
||
|
args[i].vector_1 = 1;
|
||
|
} else {
|
||
|
args[i].vector_0 = i * 2;
|
||
|
args[i].vector_1 = i * 2 + 1;
|
||
|
}
|
||
|
|
||
|
if (cause_deadlock && i % 2 == 1)
|
||
|
args[i].vector_add_order = 1;
|
||
|
else
|
||
|
args[i].vector_add_order = 0;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < 2 * MAX_THREADS; i++)
|
||
|
vector_init(&v[i], i);
|
||
|
|
||
|
double t1 = Time_GetSeconds();
|
||
|
|
||
|
for (i = 0; i < num_threads; i++)
|
||
|
Pthread_create(&pid[i], NULL, worker, (void *) &args[i]);
|
||
|
for (i = 0; i < num_threads; i++)
|
||
|
Pthread_join(pid[i], NULL);
|
||
|
|
||
|
double t2 = Time_GetSeconds();
|
||
|
|
||
|
fini();
|
||
|
if (do_timing) {
|
||
|
printf("Time: %.2f seconds\n", t2 - t1);
|
||
|
}
|
||
|
|
||
|
//vector_print(&v[0], "v1");
|
||
|
//vector_print(&v[1], "v2");
|
||
|
return 0;
|
||
|
}
|