/* POSIX thread example. See threads(3T). 1996 Nov, 2001 Apr WH Compile with -lpthread Touch up to five files /tmp/thread.* where extension * is read on stdin. Let threads complain if pathname is longer than 20 characters (a dumb limit so thread failure can be tested) and threads return the length of the file name (also dumb because main already knows this). */ #include /* for threads */ #include /* for open() */ #include #include #include /* for close() */ #include /* for malloc() */ #include /* for strcpy(), strcat(), strlen() */ #include /* for printf() and scanf() */ void *service(void *arg); /* service routine: the code for a thread */ pthread_mutex_t mp; /* mutex: MUTual EXclusion lock for file_count */ typedef struct { /* structure for use by service function */ pthread_t id; char *filename; int filelength; } THRDARG; #define MAXTHRD 5 int file_count = 0; char *base_name = "/tmp/thread."; int main() { THRDARG thrdarg[MAXTHRD]; /* array of thread arg, one for each thread */ int thrdindex = 0; char fileext[81], *filestr; int i; /* initialize the mutex called mp. We neglect to check the return value. */ pthread_mutex_init(&mp, NULL /* use default attributes */); while (scanf("%80s",fileext) == 1) { /* Obtained extension name, now generate the full file string: filestr */ filestr = malloc((strlen(base_name) + strlen(fileext) + 1)*sizeof(char)); strcpy(filestr,base_name); strcat(filestr,fileext); /* set up thread service args and create thread */ thrdarg[thrdindex].filename = filestr; if (0 != pthread_create(&(thrdarg[thrdindex].id), /* place to store ID */ NULL, /* attributes - default specified (joinable), but one could specify detached, real time, etc */ service, /* the thread code */ &thrdarg[thrdindex]) /* args for thread */ ) { /* cannot create thread - abandon everything */ fprintf(stderr,"Could not create threads\n"); exit(1); } if (++thrdindex >= MAXTHRD) break; /* too many threads */ } { /* main does nothing useful */ } /* join threads - wait for threads to finish before exiting */ for (i = 0; i < thrdindex; i++) { void *thrd_return; pthread_join(thrdarg[i].id, &thrd_return); printf("Thread number %d with ID: %ld terminated with file length %d.\n", i, /* NOT PORTABLE */ (long)thrdarg[i].id, *(int *)thrd_return); /* WARNING: although usually an int or long, thread id's need not be */ free(thrdarg[i].filename); } pthread_mutex_destroy(&mp); /* free mutex resources */ printf("Touched %d file(s) successfully.\n", file_count); exit(0); /* exit from program kills all threads. */ /* In cases where the main thread is to exit, but other threads should stay alive, use pthread_exit() here instead. */ } /* code for a thread: must always be declared as void *name(void *) */ void *service(void *arg) { THRDARG *args = arg; /* cast pointer to the right type */ int fildes; if (strlen(args->filename) > 20 || (fildes = open(args->filename,O_WRONLY|O_CREAT|O_APPEND|O_EXCL,0666)) < 0) { args->filelength = -1; printf("File %s exists already or name is longer than 20 characters.\n", args->filename); return &args->filelength; } close(fildes); /* Use the mutual exclusion lock to protect incrementing the file count */ pthread_mutex_lock(&mp); /* lock it */ file_count++; /* only one thread increments at a time */ pthread_mutex_unlock(&mp); /* unlock it */ args->filelength = strlen(args->filename); pthread_exit(& args->filelength); /* Must use return() or pthread_exit(), but not exit() from any code run by the thread. exit() will end the entire process, not just the thread. Note that the address of a NON-LOCAL variable must be used: variable = value; pthread_exit(&variable); which differs from exit() which returns just an int value! */ }