Process vs Threads, thread example
[AdSense-A]
process vs threads
Create a Thread
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
//process vs threads // thread-create.c #include <pthread.h> #include <stdio.h> /* Prints x’s to stderr. The parameter is unused. Does not return. */ void* print_xs (void* unused) { while (1) fputc (‘x’, stderr); return NULL; } /* The main program. */ int main () { pthread_t My_thread_id; /* Create a new thread. The new thread will run the print_xs function. */ pthread_create (&My_thread_id, NULL, &print_xs, NULL); /* Print o’s continuously to stderr. */ while (1) fputc (‘o’, stderr); return 0; } |
Compile and link this program using the following code:
Anand:$> cc -o thread-create thread-create.c -lpthread
[AdSense-A]
Now run the code, you will see unpredictable pattern of x’s and o’s, as Linux alternately schedules the two threads.
Create Two Threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
//process vs threads #include <pthread.h> #include <stdio.h> /* Parameters to print_function. */ struct char_print_parms { /* The character to print. */ char character; /* The number of times to print it. */ int count; }; /* Prints a number of characters to stderr, as given by PARAMETERS, which is a pointer to a struct char_print_parms. */ void* char_print (void* parameters) { /* Cast the cookie pointer to the right type. */ struct char_print_parms* p = (struct char_print_parms*) parameters; int i; for (i = 0; i < p->count; ++i) fputc (p->character, stderr); return NULL; } /* The main program. */ int main () { pthread_t My_thread_1; pthread_t My_thread_2; struct char_print_parms thread1_args; struct char_print_parms thread2_args; /* Create a new thread to print 30,000 ’x’s. */ thread1_args.character = ’x’; thread1_args.count = 30000; pthread_create (&My_thread_1, NULL, &char_print, &thread1_args); /* Create a new thread to print 20,000 o’s. */ thread2_args.character = ’o’; thread2_args.count = 20000; pthread_create (&My_thread_2, NULL, &char_print, &thread2_args); return 0; } |
[AdSense-A]
The example has a serious bug.The main thread creates the thread parameter structures (thread1_args and thread2_args) as local variables, and then passes pointers to these structures to the threads it creates.What if main thread finishes executing before either of the other two threads are done? … this could lead to problems….! The memory containing the thread parameter structures will be deallocated while the other two threads are still accessing it.
Joining Threads
One solution for above problem is to force main to wait until the other two threads are done.A function similar to wait that waits for a thread to finish instead of a process will solve this issue. That function is pthread_join, which takes two arguments: the thread ID of the thread to wait for, and a pointer to a void* variable that will receive the finished thread’s return value. If you don’t care about the thread return value, pass NULL as the second argument.Below code shows the corrected main function, here main does not exit until both of the threads printing x’s and o’s have completed, so they are no longer using the argument structures.
Revised Main Function for thread-create2.c
Create Two Threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
//process vs threads #include <pthread.h> #include <stdio.h> /* Parameters to print_function. */ struct char_print_parms { /* The character to print. */ char character; /* The number of times to print it. */ int count; }; /* Prints a number of characters to stderr, as given by PARAMETERS, which is a pointer to a struct char_print_parms. */ void* char_print (void* parameters) { /* Cast the cookie pointer to the right type. */ struct char_print_parms* p = (struct char_print_parms*) parameters; int i; for (i = 0; i < p->count; ++i) fputc (p->character, stderr); return NULL; } int main () { pthread_t My_thread_1; pthread_t My_thread_2; struct char_print_parms thread1_args; struct char_print_parms thread2_args; /* Create a new thread to print 30,000 x’s. */ thread1_args.character = ’x’; thread1_args.count = 30000; pthread_create (&My_thread_1, NULL, &char_print, &thread1_args); /* Create a new thread to print 20,000 o’s. */ thread2_args.character = ’o’; thread2_args.count = 20000; pthread_create (&My_thread_2, NULL, &char_print, &thread2_args); /* Make sure the first thread has finished. */ pthread_join (My_thread_1, NULL); /* Make sure the second thread has finished. */ pthread_join (My_thread_2, NULL); /* Now we can safely return. */ return 0; } |
[AdSense-A]
Compute Prime Numbers in a Thread
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
//process vs threads #include <pthread.h> #include <stdio.h> /* Compute successive prime numbers (not very efficiently). Return the Nth prime number, where N is the value pointed to by *ARG. */ void* compute_prime (void* arg) { int candidate = 2; int n = *((int*) arg); while (1) { int factor; int is_prime = 1; /* Test primality by successive division. */ for (factor = 2; factor < candidate; ++factor) if (candidate % factor == 0) { is_prime = 0; break; } /* Is this the prime number we’re looking for? */ if (is_prime) { if (--n == 0) /* Return the desired prime number as the thread return value. */ return (void*) candidate; } ++candidate; } return NULL; } int main () { pthread_t thread; int which_prime = 5000; int My_prime; /* Start the computing thread, up to the 5,000th prime number. */ pthread_create (&thread, NULL, &compute_prime, &which_prime); /* Do some other work here... */ /* Wait for the prime number thread to complete, and get the result. */ pthread_join (thread, (void*) &My_prime); /* Print the largest prime it computed. */ printf(“The %dth prime number is %d.\n”, which_prime, My_prime); return 0; } |
Processes Vs Threads
[AdSense-A]
For some programs that demands or need concurrency, the decision whether to use processes or threads can be difficult. Here are some guidelines to help you decide
Which concurrency model best suits your program:
- All threads in a program must run the same executable (they are all part of same process). A child process, on the other hand, may run a different executable by calling an exec function.
- An errant thread can harm other threads in the same process because threads share the same virtual memory space and other resources. For instance, a wild memory write through an uninitialized pointer in one thread can corrupt memory visible to another thread.
An errant process, on the other hand, cannot do so because each process has a copy of the program’s memory space. (So it’s safer)
- There is an additional performance overhead of copying memory for a new process relative to creating a new thread. However, the copy is performed only when the memory is changed, so the penalty is minimal if the child process only reads memory.
- Threads should be used for programs that need fine-grained parallelism. For example, if a problem can be broken into multiple, nearly identical tasks, threads may be a good choice. Processes should be used for programs that need coarser parallelism, and may be not too much data commonality.
- Sharing data among threads is trivial because threads share the same memory. (However, great care must be taken to avoid race conditions) Sharing data among processes requires the use of IPC mechanisms, like pipe, shared memory, named pipes and so on.This can be more cumbersome but makes multiple processes less likely to suffer from concurrency bugs.
Recent Comments