: Thread API”
Prev: concurrency-an-introduction Next: locks
The thread creation API in POSIX is easy:
#include <pthread.h>
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
. Creates a new thread of execution
There are four arguments: 1. a thread
, a pointer to a
pthread_t
struct, 2. an attr
,
const pthread_attr_t
struct, which specifies attributes to
build the struct 3. a void *
returning start routine that
takes any argument 4. a void *
argument, an argument to
pass to the thread.
To wait for a thread to complete, you must call
pthread_join()
.
int pthread_join(pthread_t, thread, void** value_ptr);
This returns 0 on success, or an error code.
For a full example of using a thread and joining it:
typedef struct { int a; int b; } myarg_t;
typedef struct { int x; int y; } myret_t;
void *mythread(void *arg) {
*rvals = Malloc(sizeof(myret_t));
myret_t ->x = 1;
rvals->y = 2;
rvalsreturn (void *) rvals;
}
int main(int argc, char *argv[]) {
;
pthread_t p*rvals;
myret_t = { 10, 20 };
myarg_t args (&p, NULL, mythread, &args);
Pthread_create(p, (void **) &rvals);
Pthread_join("returned %d %d\n", rvals->x, rvals->y);
printf(rvals);
free}
Make sure not to return a pointer to anything on the stack of the thread:
void *mythread(void *arg) {
*args = (myarg_t *) arg;
myarg_t ("%d %d\n", args->a, args->b);
printf; // ALLOCATED ON STACK: BAD!
myret_t oops.x = 1;
oops.y = 2;
oopsreturn (void *) &oops; // return freed memory
}
If you don’t want to pass a single argument, you can pass one number as an argument:
void *mythread(void *arg) {
long long int value = (long long int) arg;
("%lld\n", value);
printfreturn (void *) (value + 1);
}
int main(int argc, char *argv[]) {
;
pthread_t plong long int rvalue;
(&p, NULL, mythread, (void *) 100);
Pthread_create(p, (void **) &rvalue);
Pthread_join("returned %lld\n", rvalue);
printfreturn 0;
}
Locks are created and locked and unlocked.
int pthread_mutex_t lock;
int rc = pthread_mutex_init(&lock, NULL);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
To use a mutex, you’ll want to guard the critical section:
;
pthread_mutex_t lockint rc = pthread_mutex_init(&lock, NULL);
(&lock);
pthread_mutex_lock= x + 1; // or whatever your critical section is
x (&lock); pthread_mutex_unlock
There are two other interesting functions:
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_timedlock(pthread_mutex_t *mutex,
struct timespec *abs_timeout);
The trylock returns a failure if the lock is already held; the timedlock takes a timespec struct, and it returns a failure if it can’t get the lock in that time, otherwise it locks.
Condition variables are useful for signaling between threads without busy-waiting:
The two main functions are:
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_signal(pthread_cond_t *cond);
The first, puts the calling thread to sleep, and waits for another thread to signal to it.
= PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond (&lock);
Pthread_mutex_lockwhile (ready == 0)
(&cond, &lock);
Pthread_cond_wait(&lock); Pthread_mutex_unlock
The second function is used to signal to that thread.
(&lock);
Pthread_mutex_lock= 1;
ready (&cond);
Pthread_cond_signal(&lock) Pthread_mutex_unlock
Prev: concurrency-an-introduction Next: locks