pthread api
对 pthread api 进行归类, 可以分为四类:
-
线程管理
直接工作于线程, 如创建, 分离, 加入 (join) 等, 也包括设置或查询线程属性
(joinable, scheduling 等). -
互斥量
处理同步的 mutex (mutual exclusion 的缩写), 如创建互斥量, 销毁互斥量,
锁定及解锁互斥量等, 也包括互斥量属性的设置与修改. -
条件变量
处理线程之间的通信, 这些共享同一个 mutex, 如创建, 销毁, 等待, 通知
(singal), 也包括设置或查询条件变量的属性. -
同步
管理读写锁和栅栏 (barrier).
pthread 库中所有的标识都以 pthread_ 开头, 如下表所示:
前缀 | 分组 |
---|---|
pthread_ | 与线程本身相关的指令组 |
pthread_attr_ | 线程属性对象 |
pthread_mutex_ | 互斥量s |
pthread_mutexattr_ | 互斥量属性对象 |
pthread_cond_ | 条件变量 |
pthread_condattr_ | 条件变量属性对象 |
pthread_key_ | 特定于线程的数据 keys (局部存储) |
pthread_rwlock_ | 读写锁 |
pthread_barrier_ | 同步栅栏 |
创建线程终止线程
主要有下列的 api:
// 若 arg 为 NULL, 表示不向 start_routine() 传递参数
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*),
void *restrict arg);
// value_ptr 为线程退出码, 由 pthread_join() 函数的第二个参数接收.
// 在 main() 中创建了线程, 然后显式调用本函数, main() 会等其它线程
//+都结束后才会结束.
void pthread_exit(void *value_ptr);
int pthread_cancel(pthread_t thread);
int pthread_attr_destroy(pthread_attr_t *attr);
int pthread_attr_init(pthread_attr_t *attr);
例 1: Pthread Creation and Termination
#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 5
void *PrintHello(void *threadid)
{
long tid;
tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0; t<NUM_THREADS; t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL);
}
例2: Thread Argument Passing
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 8
char *messages[NUM_THREADS];
void *PrintHello(void *threadid)
{
int *id_ptr, taskid;
sleep(1);
id_ptr = (int *) threadid;
taskid = *id_ptr;
printf("Thread %d: %s\n", taskid, messages[taskid]);
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int *taskids[NUM_THREADS];
int rc, t;
messages[0] = "English: Hello World!";
messages[1] = "French: Bonjour, le monde!";
messages[2] = "Spanish: Hola al mundo";
messages[3] = "Klingon: Nuq neH!";
messages[4] = "German: Guten Tag, Welt!";
messages[5] = "Russian: Zdravstvytye, mir!";
messages[6] = "Japan: Sekai e konnichiwa!";
messages[7] = "Latin: Orbis, te saluto!";
for(t=0;t<NUM_THREADS;t++) {
taskids[t] = (int *) malloc(sizeof(int));
*taskids[t] = t;
printf("Creating thread %d\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *) taskids[t]);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL);
}
例3: Thread Argument Passing
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 8
char *messages[NUM_THREADS];
struct thread_data
{
int thread_id;
int sum;
char *message;
};
struct thread_data thread_data_array[NUM_THREADS];
void *PrintHello(void *threadarg)
{
int taskid, sum;
char *hello_msg;
struct thread_data *my_data;
sleep(1);
my_data = (struct thread_data *) threadarg;
taskid = my_data->thread_id;
sum = my_data->sum;
hello_msg = my_data->message;
printf("Thread %d: %s Sum=%d\n", taskid, hello_msg, sum);
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int *taskids[NUM_THREADS];
int rc, t, sum;
sum=0;
messages[0] = "English: Hello World!";
messages[1] = "French: Bonjour, le monde!";
messages[2] = "Spanish: Hola al mundo";
messages[3] = "Klingon: Nuq neH!";
messages[4] = "German: Guten Tag, Welt!";
messages[5] = "Russian: Zdravstvytye, mir!";
messages[6] = "Japan: Sekai e konnichiwa!";
messages[7] = "Latin: Orbis, te saluto!";
for(t=0;t<NUM_THREADS;t++) {
sum = sum + t;
thread_data_array[t].thread_id = t;
thread_data_array[t].sum = sum;
thread_data_array[t].message = messages[t];
printf("Creating thread %d\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello,
(void *) &thread_data_array[t]);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL);
}
线程管理
主要有下面 api:
// value_ptr 由 pthread_exit() 指定.
int pthread_join(pthread_t thread, void **value_ptr);
int pthread_detach(pthread_t thread);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
例 4: Pthread Joining
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define NUM_THREADS 4
void *BusyWork(void *t)
{
int i;
long tid;
double result=0.0;
tid = (long)t;
printf("Thread %ld starting...\n",tid);
for (i=0; i<1000000; i++)
{
result = result + sin(i) * tan(i);
}
printf("Thread %ld done. Result = %e\n",tid, result);
pthread_exit((void*) t);
}
int main (int argc, char *argv[])
{
pthread_t thread[NUM_THREADS];
pthread_attr_t attr;
int rc;
long t;
void *status;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for(t=0; t<NUM_THREADS; t++) {
printf("Main: creating thread %ld\n", t);
rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t);
if (rc) {
printf("ERROR; return code from pthread_create()
is %d\n", rc);
exit(-1);
}
}
pthread_attr_destroy(&attr);
for(t=0; t<NUM_THREADS; t++) {
rc = pthread_join(thread[t], &status);
if (rc) {
printf("ERROR; return code from pthread_join()
is %d\n", rc);
exit(-1);
}
printf("Main: completed join with thread %ld having a status
of %ld\n",t,(long)status);
}
printf("Main: program completed. Exiting.\n");
pthread_exit(NULL);
}
栈管理
不同的操作系统可以为线栈提供的栈大小不一样, 可以人为指定线程使用的栈大小
(要考虑操作系统的限制). 主要有下面的 api:
int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
size_t *restrict stacksize);
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstackaddr(const pthread_attr_t *restrict attr,
void **restrict stackaddr);
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr);
例 5: Stack Management
#include <pthread.h>
#include <stdio.h>
#define NTHREADS 4
#define N 1000
#define MEGEXTRA 1000000
pthread_attr_t attr;
void *dowork(void *threadid)
{
double A[N][N];
int i,j;
long tid;
size_t mystacksize;
tid = (long)threadid;
pthread_attr_getstacksize (&attr, &mystacksize);
printf("Thread %ld: stack size = %li bytes \n", tid, mystacksize);
for (i=0; i<N; i++)
for (j=0; j<N; j++)
A[i][j] = ((i*j)/3.452) + (N-i);
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
pthread_t threads[NTHREADS];
size_t stacksize;
int rc;
long t;
pthread_attr_init(&attr);
pthread_attr_getstacksize (&attr, &stacksize);
printf("Default stack size = %li\n", stacksize);
stacksize = sizeof(double)*N*N+MEGEXTRA;
printf("Amount of stack needed per thread = %li\n",stacksize);
pthread_attr_setstacksize (&attr, stacksize);
printf("Creating threads with stack size = %li bytes\n",stacksize);
for(t=0; t<NTHREADS; t++){
rc = pthread_create(&threads[t], &attr, dowork, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
printf("Created %ld threads.\n", t);
pthread_exit(NULL);
}
其它
pthread_t pthread_self(void);
int pthread_equal(pthread_t t1, pthread_t t2);
// 这是静态声明
pthread_once_t once_control = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t *once_control,
void (*init_routine)(void));
互斥量
创建与销毁互斥量
主要有下面 api:
// 这是静态声明
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
锁定与解锁互斥量
主要有下面 api:
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
例 6: Using Mutexes
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
double *a;
double *b;
double sum;
int veclen;
} DOTDATA;
#define NUMTHRDS 4
#define VECLEN 100
DOTDATA dotstr;
pthread_t callThd[NUMTHRDS];
pthread_mutex_t mutexsum;
void *dotprod(void *arg)
{
int i, start, end, len ;
long offset;
double mysum, *x, *y;
offset = (long)arg;
len = dotstr.veclen;
start = offset*len;
end = start + len;
x = dotstr.a;
y = dotstr.b;
mysum = 0;
for (i=start; i<end ; i++) {
mysum += (x[i] * y[i]);
}
pthread_mutex_lock (&mutexsum);
dotstr.sum += mysum;
pthread_mutex_unlock (&mutexsum);
pthread_exit((void*) 0);
}
int main (int argc, char *argv[])
{
long i;
double *a, *b;
void *status;
pthread_attr_t attr;
a = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));
b = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));
for (i=0; i<VECLEN*NUMTHRDS; i++) {
a[i]=1.0;
b[i]=a[i];
}
dotstr.veclen = VECLEN;
dotstr.a = a;
dotstr.b = b;
dotstr.sum=0;
pthread_mutex_init(&mutexsum, NULL);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for(i=0; i<NUMTHRDS; i++) {
pthread_create(&callThd[i], &attr, dotprod, (void *)i);
}
pthread_attr_destroy(&attr);
for(i=0; i<NUMTHRDS; i++) {
pthread_join(callThd[i], &status);
}
printf ("Sum = %f \n", dotstr.sum);
free (a);
free (b);
pthread_mutex_destroy(&mutexsum);
pthread_exit(NULL);
}
条件变量
创建与销毁条件变量
主要有下面 api:
// 这是静态声明
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
int pthread_condattr_destroy(pthread_condattr_t *attr);
int pthread_condattr_init(pthread_condattr_t *attr);
等待与通知
主要有下面 api:
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
例 7: Using Condition Variables
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 3
#define TCOUNT 10
#define COUNT_LIMIT 12
int count = 0;
int thread_ids[3] = {0,1,2};
pthread_mutex_t count_mutex;
pthread_cond_t count_threshold_cv;
void *inc_count(void *t)
{
int i;
long my_id = (long)t;
for (i=0; i<TCOUNT; i++) {
pthread_mutex_lock(&count_mutex);
count++;
if (count == COUNT_LIMIT) {
pthread_cond_signal(&count_threshold_cv);
printf("inc_count(): thread %ld, count = %d Threshold reached.\n",
my_id, count);
}
printf("inc_count(): thread %ld, count = %d, unlocking mutex\n",
my_id, count);
pthread_mutex_unlock(&count_mutex);
sleep(1);
}
pthread_exit(NULL);
}
void *watch_count(void *t)
{
long my_id = (long)t;
printf("Starting watch_count(): thread %ld\n", my_id);
pthread_mutex_lock(&count_mutex);
while (count<COUNT_LIMIT) {
pthread_cond_wait(&count_threshold_cv, &count_mutex);
printf("watch_count(): thread %ld Condition signal received.\n", my_id);
count += 125;
printf("watch_count(): thread %ld count now = %d.\n", my_id, count);
}
pthread_mutex_unlock(&count_mutex);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
int i, rc;
long t1=1, t2=2, t3=3;
pthread_t threads[3];
pthread_attr_t attr;
pthread_mutex_init(&count_mutex, NULL);
pthread_cond_init (&count_threshold_cv, NULL);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&threads[0], &attr, watch_count, (void *)t1);
pthread_create(&threads[1], &attr, inc_count, (void *)t2);
pthread_create(&threads[2], &attr, inc_count, (void *)t3);
for (i=0; i<NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
printf ("Main(): Waited on %d threads. Done.\n", NUM_THREADS);
/* Clean up and exit */
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&count_mutex);
pthread_cond_destroy(&count_threshold_cv);
pthread_exit(NULL);
}
所有库函数
int pthread_atfork (void (*prepare)(void),
void (*parent)(void),
void (*child)(void));
int pthread_attr_destroy (pthread_attr_t *attr);
int pthread_attr_getdetachstate (const pthread_attr_t *attr,
int *detachstate);
int pthread_attr_getguardsize (const pthread_attr_t *restrict attr,
size_t *restrict guardsize);
int pthread_attr_getinheritsched (const pthread_attr_t *restrict attr,
int *restrict inheritsched);
int pthread_attr_getschedparam (const pthread_attr_t *restrict attr,
struct sched_param *restrict param);
int pthread_attr_getschedpolicy (const pthread_attr_t *restrict attr,
int *restrict policy);
int pthread_attr_getscope (const pthread_attr_t *restrict attr,
int *restrict contentionscope);
int pthread_attr_getstack (const pthread_attr_t *restrict attr,
void **restrict stackaddr,
size_t *restrict stacksize);
int pthread_attr_getstackaddr (const pthread_attr_t *restrict attr,
void **restrict stackaddr);
int pthread_attr_getstacksize (const pthread_attr_t *restrict attr,
size_t *restrict stacksize);
int pthread_attr_init (pthread_attr_t *attr);
int pthread_attr_setdetachstate (pthread_attr_t *attr,
int detachstate);
int pthread_attr_setguardsize (pthread_attr_t *attr,
size_t guardsize);
int pthread_attr_setinheritsched (pthread_attr_t *attr,
int inheritsched);
int pthread_attr_setschedparam (pthread_attr_t *restrict attr,
const struct sched_param *restrict param);
int pthread_attr_setschedpolicy (pthread_attr_t *attr,
int policy);
int pthread_attr_setscope (pthread_attr_t *attr,
int contentionscope);
int pthread_attr_setstack (pthread_attr_t *attr,
void *stackaddr,
size_t stacksize);
int pthread_attr_setstackaddr (pthread_attr_t *attr,
void *stackaddr);
int pthread_attr_setstacksize (pthread_attr_t *attr,
size_t stacksize);
int pthread_barrier_destroy (pthread_barrier_t *barrier);
int pthread_barrier_init (pthread_barrier_t *restrict barrier,
const pthread_barrierattr_t *restrict attr,
unsigned count);
int pthread_barrier_wait (pthread_barrier_t *barrier);
int pthread_barrierattr_destroy (pthread_barrierattr_t *attr);
int pthread_barrierattr_getpshared (const pthread_barrierattr_t * restrict attr,
int *restrict pshared);
int pthread_barrierattr_init (pthread_barrierattr_t *attr);
int pthread_barrierattr_setpshared (pthread_barrierattr_t *attr,
int pshared);
int pthread_cancel (pthread_t thread);
int pthread_cond_broadcast (pthread_cond_t *cond);
int pthread_cond_destroy (pthread_cond_t *cond);
int pthread_cond_init (pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
int pthread_cond_signal (pthread_cond_t *cond);
int pthread_cond_timedwait (pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
int pthread_cond_wait (pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
int pthread_condattr_destroy (pthread_condattr_t *attr);
int pthread_condattr_getclock (const pthread_condattr_t *restrict attr,
clockid_t *restrict clock_id);
int pthread_condattr_getpshared (const pthread_condattr_t *restrict attr,
int *restrict pshared);
int pthread_condattr_init (pthread_condattr_t *attr);
int pthread_condattr_setclock (pthread_condattr_t *attr,
clockid_t clock_id);
int pthread_condattr_setpshared (pthread_condattr_t *attr,
int pshared);
int pthread_create (pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*),
void *restrict arg);
int pthread_detach (pthread_t thread);
int pthread_equal (pthread_t t1,
pthread_t t2);
int pthread_getconcurrency (void);
int pthread_getcpuclockid (pthread_t thread_id,
clockid_t *clock_id);
int pthread_getschedparam (pthread_t thread,
int *restrict policy,
struct sched_param *restrict param);
int pthread_join (pthread_t thread,
void **value_ptr);
int pthread_key_create (pthread_key_t *key,
void (*destructor)(void*));
int pthread_key_delete (pthread_key_t key);
int pthread_kill (pthread_t thread,
int sig);
int pthread_mutex_destroy (pthread_mutex_t *mutex);
int pthread_mutex_getprioceiling (const pthread_mutex_t *restrict mutex,
int *restrict prioceiling);
int pthread_mutex_init (pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
int pthread_mutex_lock (pthread_mutex_t *mutex);
int pthread_mutex_setprioceiling (pthread_mutex_t *restrict mutex,
int prioceiling,
int *restrict old_ceiling);
int pthread_mutex_timedlock (pthread_mutex_t *restrict mutex,
const struct timespec *restrict abs_timeout);
int pthread_mutex_trylock (pthread_mutex_t *mutex);
int pthread_mutex_unlock (pthread_mutex_t *mutex);
int pthread_mutexattr_destroy (pthread_mutexattr_t *attr);
int pthread_mutexattr_getprioceiling (const pthread_mutexattr_t * restrict attr,
int *restrict prioceiling);
int pthread_mutexattr_getprotocol (const pthread_mutexattr_t * restrict attr,
int *restrict protocol);
int pthread_mutexattr_getpshared (const pthread_mutexattr_t * restrict attr,
int *restrict pshared);
int pthread_mutexattr_gettype (const pthread_mutexattr_t *restrict attr,
int *restrict type);
int pthread_mutexattr_init (pthread_mutexattr_t *attr);
int pthread_mutexattr_setprioceiling (pthread_mutexattr_t *attr,
int prioceiling);
int pthread_mutexattr_setprotocol (pthread_mutexattr_t *attr,
int protocol);
int pthread_mutexattr_setpshared (pthread_mutexattr_t *attr,
int pshared);
int pthread_mutexattr_settype (pthread_mutexattr_t *attr,
int type);
int pthread_once (pthread_once_t *once_control,
void (*init_routine)(void));
int pthread_rwlock_destroy (pthread_rwlock_t *rwlock);
int pthread_rwlock_init (pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock);
int pthread_rwlock_timedrdlock (pthread_rwlock_t *restrict rwlock,
const struct timespec *restrict abs_timeout);
int pthread_rwlock_timedwrlock (pthread_rwlock_t *restrict rwlock,
const struct timespec *restrict abs_timeout);
int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock (pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock);
int pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr);
int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * restrict attr,
int *restrict pshared);
int pthread_rwlockattr_init (pthread_rwlockattr_t *attr);
int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr,
int pshared);
int pthread_setcancelstate (int state,
int *oldstate);
int pthread_setcanceltype (int type,
int *oldtype);
int pthread_setconcurrency (int new_level);
int pthread_setschedparam (pthread_t thread,
int policy,
const struct sched_param *param);
int pthread_setschedprio (pthread_t thread,
int prio);
int pthread_setspecific (pthread_key_t key,
const void *value);
int pthread_sigmask (int how,
const sigset_t *restrict set,
sigset_t *restrict oset);
int pthread_spin_destroy (pthread_spinlock_t *lock);
int pthread_spin_init (pthread_spinlock_t *lock,
int pshared);
int pthread_spin_lock (pthread_spinlock_t *lock);
int pthread_spin_trylock (pthread_spinlock_t *lock);
int pthread_spin_unlock (pthread_spinlock_t *lock);
int sigprocmask (int how,
const sigset_t *restrict set,
sigset_t *restrict oset);
pthread_t pthread_self (void);
void *pthread_getspecific (pthread_key_t key);
void pthread_cleanup_pop (int execute);
void pthread_cleanup_push (void (*routine)(void*),
void *arg);
void pthread_exit (void *value_ptr);
void pthread_testcancel (void);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_once_t once_control = PTHREAD_ONCE_INIT;
``