concurrency: different things happening at once
parallelism: do same thing with more resources
void *ComputePi(void *argument) { ... }
void *PrintClassList(void *argument) { ... }
int main() {
pthread_t pi_thread, list_thread;
if (0 != pthread_create(&pi_thread, NULL, ComputePi, NULL))
handle_error();
if (0 != pthread_create(&list_thread, NULL, PrintClassList, NULL))
handle_error();
... /* more code */
}
void *ComputePi(void *argument) { ... }
void *PrintClassList(void *argument) { ... }
int main() {
pthread_t pi_thread, list_thread;
if (0 != pthread_create(&pi_thread, NULL, ComputePi, NULL))
handle_error();
if (0 != pthread_create(&list_thread, NULL, PrintClassList, NULL))
handle_error();
... /* more code */
}
#include <pthread.h>
#include <stdio.h>
void *print_message(void *ignored_argument) {
printf("In the thread\n");
return NULL;
}
int main() {
printf("About to start thread\n");
pthread_t the_thread;
/* assume does not fail */
pthread_create(&the_thread, NULL, print_message, NULL);
printf("Done starting thread\n");
return 0;
}
My machine: outputs In the thread about 4% of the time.
What happened?
#include <pthread.h>
#include <stdio.h>
void *print_message(void *ignored_argument) {
printf("In the thread\\n");
return NULL;
}
int main() {
printf("About to start thread\\n");
pthread_t the_thread;
/* missing: error checking */
pthread_create(&the_thread, NULL, print_message, NULL);
printf("Done starting thread\\n");
pthread_join(the_thread, NULL); /* WAIT FOR THREAD */
return 0;
}
#include <pthread.h>
#include <stdio.h>
void *print_message(void *ignored_argument) {
printf("In the thread\\n");
return NULL;
}
int main() {
printf("About to start thread\\n");
pthread_t the_thread;
/* missing: error checking */
pthread_create(&the_thread, NULL, print_message, NULL);
printf("Done starting thread\\n");
pthread_exit(NULL);
}
R = pthread_join(X, &P): wait for thread X, copies return value into P
waitpid, but for a threadpthread_exit: exit current thread, returning a value
exit or returning from main, but for a single threadint values[1024]; int results[2];
void *sum_front(void *ignored_argument) {
int sum = 0;
for (int i = 0; i < 512; ++i) { sum += values[i]; }
results[0] = sum;
return NULL;
}
void *sum_back(void *ignored_argument) {
int sum = 0;
for (int i = 512; i < 1024; ++i) { sum += values[i]; }
results[1] = sum;
return NULL;
}
int sum_all() {
pthread_t sum_front_thread, sum_back_thread;
/* missing: error handling */
pthread_create(&sum_front_thread, NULL, sum_front, NULL);
pthread_create(&sum_back_thread, NULL, sum_back, NULL);
pthread_join(sum_front_thread, NULL); pthread_join(sum_back_thread, NULL);
return results[0] + results[1];
}
int values[1024]; int results[2];
void *sum_front(void *ignored_argument) {
int sum = 0;
for (int i = 0; i < 512; ++i) { sum += values[i]; }
results[0] = sum;
return NULL;
}
void *sum_back(void *ignored_argument) {
int sum = 0;
for (int i = 512; i < 1024; ++i) { sum += values[i]; }
results[1] = sum;
return NULL;
}
int sum_all() {
pthread_t sum_front_thread, sum_back_thread;
/* missing: error handling */
pthread_create(&sum_front_thread, NULL, sum_front, NULL);
pthread_create(&sum_back_thread, NULL, sum_back, NULL);
pthread_join(sum_front_thread, NULL); pthread_join(sum_back_thread, NULL);
return results[0] + results[1];
}
values, results: global variables
shared between all threads
int values[1024]; int results[2];
void *sum_front(void *ignored_argument) {
int sum = 0;
for (int i = 0; i < 512; ++i) { sum += values[i]; }
results[0] = sum;
return NULL;
}
void *sum_back(void *ignored_argument) {
int sum = 0;
for (int i = 512; i < 1024; ++i) { sum += values[i]; }
results[1] = sum;
return NULL;
}
int sum_all() {
pthread_t sum_front_thread, sum_back_thread;
/* missing: error handling */
pthread_create(&sum_front_thread, NULL, sum_front, NULL);
pthread_create(&sum_back_thread, NULL, sum_back, NULL);
pthread_join(sum_front_thread, NULL); pthread_join(sum_back_thread, NULL);
return results[0] + results[1];
}
two functions — same except some numbers
values returned from via global array results
used here instead of return value
(partly to illustrate memory is shared;
partly for later version that doesn’t join)
int values[1024];
int results[2];
void *sum_thread(void *argument) {
int id = (int) argument;
int sum = 0;
for (int i = id * 512; i < (id + 1) * 512; ++i) {
sum += values[i];
}
results[id] = sum;
return NULL;
}
int sum_all() {
/* missing: error handling */
pthread_t thread[2];
for (int i = 0; i < 2; ++i) {
pthread_create(&threads[i], NULL, sum_thread, (void *) i);
}
for (int i = 0; i < 2; ++i)
pthread_join(threads[i], NULL);
return results[0] + results[1];
}
pass thread index (as fake pointer “address”)
int values[1024];
struct ThreadInfo {
int start, end, result;
};
void *sum_thread(void *argument) {
struct ThreadInfo *my_info = (struct ThreadInfo *) argument;
int sum = 0;
for (int i = my_info->start; i < my_info->end; ++i) { sum += values[i]; }
my_info->result = sum;
return NULL;
}
int sum_all() {
pthread_t thread[2]; struct ThreadInfo info[2];
for (int i = 0; i < 2; ++i) {
info[i].start = i*512; info[i].end = (i+1)*512;
pthread_create(&threads[i], NULL, sum_thread, &info[i]);
}
for (int i = 0; i < 2; ++i) { pthread_join(threads[i], NULL); }
return info[0].result + info[1].result;
}
int values[1024];
struct ThreadInfo {
int start, end, result;
};
void *sum_thread(void *argument) {
struct ThreadInfo *my_info = (struct ThreadInfo *) argument;
int sum = 0;
for (int i = my_info->start; i < my_info->end; ++i) { sum += values[i]; }
my_info->result = sum;
return NULL;
}
int sum_all() {
pthread_t thread[2]; struct ThreadInfo info[2];
for (int i = 0; i < 2; ++i) {
info[i].start = i*512; info[i].end = (i+1)*512;
pthread_create(&threads[i], NULL, sum_thread, &info[i]);
}
for (int i = 0; i < 2; ++i) { pthread_join(threads[i], NULL); }
return info[0].result + info[1].result;
}
my_info = pointer to sum_all’s stack
okay because sum_all doesn’t return until thread is done
struct ThreadInfo { int *values; int start; int end; int result };
void *sum_thread(void *argument) {
ThreadInfo *my_info = (ThreadInfo *) argument;
int sum = 0;
for (int i = my_info->start; i < my_info->end; ++i) {
sum += my_info->values[i];
}
my_info->result = sum;
return NULL;
}
int sum_all(int *values) {
ThreadInfo info[2]; pthread_t thread[2];
for (int i = 0; i < 2; ++i) {
info[i].values = values; info[i].start = i*512; info[i].end = (i+1)*512;
pthread_create(&threads[i], NULL, sum_thread, (void *) &info[i]);
}
for (int i = 0; i < 2; ++i)
pthread_join(threads[i], NULL);
return info[0].result + info[1].result;
}
struct ThreadInfo {
pthread_t thread;
int *values; int start; int end; int result;
};
void *sum_thread(void *argument) { ... }
struct ThreadInfo *start_sum_all(int *values) {
struct ThreadInfo *info = calloc(2, sizeof(struct ThreadInfo));
for (int i = 0; i < 2; ++i) {
info[i].values = values; info[i].start = i*512; info[i].end = (i+1)*512;
pthread_create(&info[i].thread, NULL, sum_thread, (void *) &info[i]);
}
return info;
}
int finish_sum_all(ThreadInfo *info) {
for (int i = 0; i < 2; ++i)
pthread_join(info[i].thread, NULL);
int result = info[0].result + info[1].result;
free(info);
return result;
}
/* omitted: headers */
void *create_string(void *ignored_argument) {
char string[1024];
ComputeString(string);
return string;
}
int main() {
pthread_t the_thread;
pthread_create(&the_thread, NULL, create_string, NULL);
char *string_ptr;
pthread_join(the_thread, (void**) &string_ptr);
printf("string is %s\n", string_ptr);
}void *show_progress(void * ...) { ... }
void spawn_show_progress_thread() {
pthread_t show_progress_thread;
pthread_create(&show_progress_thread, NULL,
show_progress, NULL);
/* instead of keeping pthread_t around to join thread later: */
pthread_detach(show_progress_thread);]
}
int main() {
spawn_show_progress_thread();
do_other_stuff();
...
}detach = don’t care about return value, etc.
system will decallocate when thread terminates
void *show_progress(void * ...) { ... }
void spawn_show_progress_thread() {
pthread_t show_progress_thread;
pthread_attr_t attrs;
pthread_attr_init(&attrs);
pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
pthread_create(&show_progress_thread, attrs,
show_progress, NULL);
pthread_attr_destroy(&attrs);
}