Consider the fork_example.c code (under "Example code for processes" on Canvas). How many processes and threads are created? (code also shown below) #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <inttypes.h> /* for PRIxPTR */ #include <pthread.h> // On Linux we need these for waitpid() #include <sys/types.h> #include <sys/wait.h> // On Solaris, this cleans up format warnings from GCC #define PID (int) getpid() // process identity, for output only char *me = "parent"; // or, "child" /* function prototype for thread creation */ void * thread_func(void * arg); /* data for threads */ struct thread_struct { pthread_t tid; // system-assigned thread identifier int num; // our own thread number int in; // input data int out; // output data }; struct thread_struct bogus = { 0, 0, 0, -1 }; pthread_attr_t attr; // thread attributes, not used here struct thread_struct in[2]; void thread_generator(int low, int high, char *identifier) { for (int i = low; i < high; i++) { in[i].tid = (pthread_t) (-1); // assigned later in[i].num = i; in[i].in = i+1; in[i].out = -1; printf("[pid %d] %s %s: pthread_create(%d): tryingn", PID, me, identifier, in[i].num); // pthread_create(&in[i].tid, &attr, thread_func, &in[i]); int ret = pthread_create(&in[i].tid, NULL, thread_func, &in[i]); // in[i].tid = identifier of new thread // the new thread executes thread_func(&in[i]) // pthread_create() returns an int, equal to 0 or error number if (ret == 0) { printf("[pid %d] %s %s: pthread_create(%d): okn", PID, me, identifier, in[i].num); } else { printf("[pid %d] %s %s: pthread_create(%d): failed: %sn", PID, me, identifier, in[i].num, strerror(ret)); } } } void thread_collector(int low, int high, char *identifier) { for (int i = low; i < high; i++) { printf("[pid %d] %s %s: pthread_join(%d): tryingn", PID, me, identifier, in[i].num); void *out = &bogus; int ret = pthread_join(in[i].tid, &out); // out = exit status from pthread_exit() // pthread_join() returns an int, equal to 0 or error number if (ret == 0) { printf("[pid %d] %s %s: pthread_join(%d): ok, exit status = %p, out = %dn", PID, me, identifier, in[i].num, out, in[i].out); } else { printf("[pid %d] %s %s: pthread_join(%d): failed: %s, exit status = %p, out = %dn", PID, me, identifier, in[i].num, strerror(ret), out, in[i].out); } } } int main(int argc, char * argv[]) { printf("[pid %d] %s: &bogus = %pn", PID, me, &bogus); for (int i = 0; i < 2; i++) { printf("[pid %d] %s: &in[%d] = %pn", PID, me, i, &in[i]); } for (int i = 0; i < 2; i++) { in[i].tid = (pthread_t) (-1); // assigned later in[i].num = i; in[i].in = -1; in[i].out = -1; } // create two threads thread_generator(0, 2, "main pre-fork"); pid_t pid = fork(); if (pid < 0) { printf("[pid %d] %s: main, fork(): failed: %sn", PID, me, strerror(errno)); } else if (pid == 0) { me = "child"; printf("[pid %d] %s: main, parent is %dn", PID, me, (int) getppid()); } else { printf("[pid %d] %s: main, child is %dn", P.