Posix Thread Tutorial

Posix thread tutorial

Lawrence Livermore National Laboratory has an excellent tutorial at:

https://computing.llnl.gov/tutorials/pthreads/

Pthread Programming Short Example

First of all, your threads return garbage. Deferencing the pointer returned would be Undefined Behaviour because it points to storage that no longer exists after the function returns. Good thing nothing used the pointer.

Next, the threads don't print anything because snprintf outputs to an array, not stdout.

Furthermore, the threads would print garbage if you switched to printf because the same pointer is passed to to all threads.

And that's assuming the threads have a chance to run since main doesn't wait for the threads to finish. You gotta join them.

Fixed:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

#define N 5

static void *run(void *arg) {
size_t job = *(size_t*)arg;
printf("Job %zu\n", job);
return NULL;
}

int main(int argc, char *argv[]) {
size_t jobs[N];
pthread_t threads[N];
for (size_t i=0; i<N; ++i) {
jobs[i] = i;
pthread_create(threads+i, NULL, run, jobs+i);
}

for (size_t i=0; i<N; ++i) {
pthread_join(threads[i]);
}

return EXIT_SUCCESS;
}

It's also common to pass an integer cast to a pointer.

#include <inttypes.h>
#include <pthread.h>
#include <stdio.h>
#include <stdint.h>

static void *run(void *arg) {
size_t job = *(uintptr_t*)arg;
printf("Job %" PRIuPTR "\n", job);
return NULL;
}

int main(int argc, char *argv[]) {
pthread_t threads[N];
for (uintptr_t i=0; i<N; ++i) {
pthread_create(threads+i, NULL, run, (void*)i);
}

for (uintptr_t i=0; i<N; ++i) {
pthread_join(threads[i]);
}

return EXIT_SUCCESS;
}

How to make multiple POSIX threads wait for another to begin

You can use barriers.

From the pthread Barriers section of randu.org's pthread tutorial:

pthreads can participate in a barrier to synchronize to some point in time. Barrier objects are initialized like mutexes or condition variables, except there is one additional parameter, count. The count variable defines the number threads that must join the barrier for the barrier to reach completion and unblock all threads waiting at the barrier.

In other words, you can create a barrier with n and any threads that calls pthread_barrier_wait will wait until n calls to pthread_barrier_wait have been made.

Below is a simple example where all three threads will print "Before" prior to any thread printing "After".

#include <pthread.h>
#include <stdio.h>

pthread_barrier_t barrier;

void* foo(void* msg) {
printf("%s: before\n", (char*)msg);

// No thread will move on until all three threads have reached this point
pthread_barrier_wait(&barrier);

printf("%s: after\n", (char*)msg);
}

int main() {

// Declare three threads
int count = 3;
pthread_t person_A, person_B, elevator;

// Create a barrier that waits for three threads
pthread_barrier_init(&barrier, NULL, count);

// Create three threads
pthread_create(&person_A, NULL, foo, "personA");
pthread_create(&person_B, NULL, foo, "personB");
pthread_create(&elevator, NULL, foo, "elevator");

pthread_join(person_A, NULL);
pthread_join(person_B, NULL);
pthread_join(elevator, NULL);
printf("end\n");
}

Run the code here

POSIX pthread programming

There are mainly two approaches for thread termination.

  • Use a cancellation point. The thread will terminate when requested to cancel and it reaches a cancellation point, thus ending execution in a controlled fashion;
  • Use a signal. Have the threads install a signal handler which provides a mechanism for termination (setting a flag and reacting to EINTR).

Both approaches has caveats. Refer to Kill Thread in Pthread Library for more details.

In your case, it seems a good opportunity to use cancellation points. I will work with a commented example. The error-checking has been omitted for clarity.

#define _POSIX_C_SOURCE 200809L
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void sigint(int signo) {
(void)signo;
}

void *thread(void *argument) {
(void)argument;
for (;;) {
// Do something useful.
printf("Thread %u running.\n", *(unsigned int*)argument);

// sleep() is a cancellation point in this example.
sleep(1);
}
return NULL;
}

int main(void) {
// Block the SIGINT signal. The threads will inherit the signal mask.
// This will avoid them catching SIGINT instead of this thread.
sigset_t sigset, oldset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
pthread_sigmask(SIG_BLOCK, &sigset, &oldset);

// Spawn the two threads.
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, thread, &(unsigned int){1});
pthread_create(&thread2, NULL, thread, &(unsigned int){2});

// Install the signal handler for SIGINT.
struct sigaction s;
s.sa_handler = sigint;
sigemptyset(&s.sa_mask);
s.sa_flags = 0;
sigaction(SIGINT, &s, NULL);

// Restore the old signal mask only for this thread.
pthread_sigmask(SIG_SETMASK, &oldset, NULL);

// Wait for SIGINT to arrive.
pause();

// Cancel both threads.
pthread_cancel(thread1);
pthread_cancel(thread2);

// Join both threads.
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);

// Done.
puts("Terminated.");
return EXIT_SUCCESS;
}

The need for blocking/unblocking signals is that if you send SIGINT to the process, any thread may be able to catch it. You do so before spawning the threads to avoid having them doing it by themselves and needing to synchronize with the parent. After the threads are created, you restore the mask and install a handler.

Cancellation points can be tricky if the threads allocates a lot of resources; in that case, you will have to use pthread_cleanup_push() and pthread_cleanup_pop(), which are a mess. But the approach is feasible and rather elegant if used properly.

Integrating pthread_create() and pthread_join() in the same loop

I figured it out. For other users with same question, I am writing below the answer.

If we put the pthread_join() in the same loop with pthread_create(), the calling thread i.e. main() will wait for the thread 0 to finish its work before creating the thread 1. This would force the threads to execute sequentially, not in parallel. Thus it would kill the purpose of multi-threading.

pthreads in C: How can I stop the threads from interfering with each other?

Each of your threads gets a pointer to the very same local variable apple_num which is being changed in the loop by the main thread. Since threads start asynchronously, the value of local variable apple_num in the main thread is indeterminate from the perspective of any other thread.

You need to pass a copy of that variable to each thread.

One fix is to cast int to void* and back:

void *apples(void* apple_num){
int thread_num = (int)void_apple_num;
...
pthread_create(&threads[apple_num], NULL, apples, (void*)apple_num);

As they mention in the comments, intptr_t and uintptr_t (from <stdint.h>) may be more appropriate for round-trip without loss, e.g. uintptr_t -> void* -> uintptr_t. But C standard doesn't require any integers to round-trip to void* and back, it only requires void* -> intptr_t and back.

In a more realistic scenario, you may like to pass more than just one integer to a thread, namely, a struct. And that's the rationale for the thread start function to receive a single void* argument - it can point to an object of any data type (POSIX requires void* to also be able to store function pointers).

An example of passing a structure to a thread (without relying on implementation-defined conversion of integers to void* and back):

struct ThreadArgs {
int thread_num;
// More data members, as needed.
};

void* apples(void* arg){
struct ThreadArgs* a = arg;
printf("Thread: %d\n", a->thread_num);
free(arg);
return NULL;
}

int main() {
pthread_t threads[6];
struct ThreadArgs* a;
int apple_num;

for(apple_num=0; apple_num<6; apple_num++){
a = malloc(sizeof *a);
a->thread_num = apple_num;
pthread_create(&threads[apple_num], NULL, apples, a);
}

for(apple_num=0; apple_num<6; apple_num++)
pthread_join(threads[apple_num], NULL);

return 0;
}

Note, that you don't have to allocate the thread arguments structure on the heap (malloc). If you pass an automatic variable (on the stack) to a thread, you must make sure that the variable is unchanged and still exists when the thread accesses it. Allocating the thread arguments structure from the heap is the safest and solves this problem at the expense of malloc/free calls.

How can you dereference and use a matrix you passed to a POSIX thread in C?

int i = 10;
int j = 10;

int var = 0;
int w,x;

Globals: just say no.

They're not generally a great idea in single-threaded programs, but using mutable globals (which start off uninitialized) in multiple threads is ... risky.

void * fillcell(void * param) {
int** value = (int**) param;
value[x][w]= x*w;

your program has a single variable x, and a single variable w. They're shared between all threads. Creating a thread doesn't create a snapshot of all global variables for the new thread's use, they're all just shared. There is absolutely no way to know, in this program, what values of x and w a given thread will see in this function.

You can fix this by passing an explicit {x, w, A} parameter structure to each thread - and I mean a different instance of that structure for each thread.

Finally, int A[10][10] is not an int**, and it doesn't decay to one. To prove this, just print the address of each A[x][w] and then print the address of each value[x][w]. See how your 2D array is really laid out. Printing all your addresses will also make it easy to understand the address valgrind is complaining about.



Related Topics



Leave a reply



Submit