1.线程限制
某些系统有线程的限制,可以通过sysconf函数来查询
2.线程属性
如想修改线程的属性,则可以在pthread_create调用时,传递pthread_attr_t类型指针参数
#include <pthread.h> int pthread_attr_init(pthread_attr_t *attr); int pthread_attr_destroy(pthread_attr_t *attr); |
Both return: 0 if OK, error number on failure |
1)设置线程的分离状态
#include <pthread.h> int pthread_attr_getdetachstate(const pthread_attr_t *restrict attr, int *detachstate); int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); |
Both return: 0 if OK, error number on failure |
例:以分离的状态创建线程
#include "apue.h" #include <pthread.h> int makethread(void *(*fn)(void *), void *arg) { int err; pthread_t tid; pthread_attr_t attr; err = pthread_attr_init(&attr); if (err != 0) return(err); err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (err == 0) err = pthread_create(&tid, &attr, fn, arg); pthread_attr_destroy(&attr); return(err); }
2)线程栈的操作接口
#include <pthread.h> int pthread_attr_getstack(const pthread_attr_t *restrict attr, void **restrict stackaddr, size_t *restrict stacksize); int pthread_attr_setstack(const pthread_attr_t *attr, void *stackaddr, size_t *stacksize); |
Both return: 0 if OK, error number on failure |
#include <pthread.h> 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); |
Both return: 0 if OK, error number on failure |
3)guardsize,线程栈末尾之后用以避免栈溢出的扩展内存区
#include <pthread.h> int pthread_attr_getguardsize(const pthread_attr_t *restrict attr, size_t *restrict guardsize); int pthread_attr_setguardsize(pthread_attr_t *attr , size_t guardsize); |
Both return: 0 if OK, error number on failure |
4)并发度
#include <pthread.h> int pthread_getconcurrency(void); |
Returns: current concurrency level |
int pthread_setconcurrency(int level);
|
Returns: 0 if OK, error number on failure |
3.同步属性
1)互斥量属性
#include <pthread.h> int pthread_mutexattr_init(pthread_mutexattr_t *attr); int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); |
Both return: 0 if OK, error number on failure |
主要注意进程共享属性和类型属性
#include <pthread.h> int pthread_mutexattr_getpshared(const pthread_mutexattr_t * restrict attr, int *restrict pshared); int pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared); |
Both return: 0 if OK, error number on failure |
#include <pthread.h> int pthread_mutexattr_gettype(const pthread_mutexattr_t * restrict attr, int *restrict type); int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type); |
Both return: 0 if OK, error number on failure |
例:使用递归锁
#include "apue.h" #include <pthread.h> #include <time.h> #include <sys/time.h> extern int makethread(void *(*)(void *), void *); struct to_info { void (*to_fn)(void *); /* function */ void *to_arg; /* argument */ struct timespec to_wait; /* time to wait */ }; #define SECTONSEC 1000000000 /* seconds to nanoseconds */ #define USECTONSEC 1000 /* microseconds to nanoseconds */ void * timeout_helper(void *arg) { struct to_info *tip; tip = (struct to_info *)arg; nanosleep(&tip->to_wait, NULL); (*tip->to_fn)(tip->to_arg); return(0); } void timeout(const struct timespec *when, void (*func)(void *), void *arg) { struct timespec now; struct timeval tv; struct to_info *tip; int err; gettimeofday(&tv, NULL); now.tv_sec = tv.tv_sec; now.tv_nsec = tv.tv_usec * USECTONSEC; if ((when->tv_sec > now.tv_sec) || (when->tv_sec == now.tv_sec && when->tv_nsec > now.tv_nsec)) { tip = malloc(sizeof(struct to_info)); if (tip != NULL) { tip->to_fn = func; tip->to_arg = arg; tip->to_wait.tv_sec = when->tv_sec - now.tv_sec; if (when->tv_nsec >= now.tv_nsec) { tip->to_wait.tv_nsec = when->tv_nsec - now.tv_nsec; } else { tip->to_wait.tv_sec--; tip->to_wait.tv_nsec = SECTONSEC - now.tv_nsec + when->tv_nsec; } err = makethread(timeout_helper, (void *)tip); if (err == 0) return; } } /* * We get here if (a) when <= now, or (b) malloc fails, or * (c) we can't make a thread, so we just call the function now. */ (*func)(arg); } pthread_mutexattr_t attr; pthread_mutex_t mutex; void retry(void *arg) { pthread_mutex_lock(&mutex); /* perform retry steps ... */ pthread_mutex_unlock(&mutex); } int main(void) { int err, condition, arg; struct timespec when; if ((err = pthread_mutexattr_init(&attr)) != 0) err_exit(err, "pthread_mutexattr_init failed"); if ((err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) != 0) err_exit(err, "can't set recursive type"); if ((err = pthread_mutex_init(&mutex, &attr)) != 0) err_exit(err, "can't create recursive mutex"); /* ... */ pthread_mutex_lock(&mutex); /* ... */ if (condition) { /* calculate target time "when" */ timeout(&when, retry, (void *)arg); } /* ... */ pthread_mutex_unlock(&mutex); /* ... */ exit(0); }
2)读写锁属性
#include <pthread.h> int pthread_rwlockattr_init(pthread_rwlockattr_t *attr); int pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr); |
Both return: 0 if OK, error number on failure |
#include <pthread.h> int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t * restrict attr, int *restrict pshared); int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared); |
Both return: 0 if OK, error number on failure |
3)条件变量属性
#include <pthread.h> int pthread_condattr_init(pthread_condattr_t *attr); int pthread_condattr_destroy(pthread_condattr_t *attr); |
Both return: 0 if OK, error number on failure |
#include <pthread.h> int pthread_condattr_getpshared(const pthread_condattr_t * restrict attr, int *restrict pshared); int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared); |
Both return: 0 if OK, error number on failure |
4.重入
一个函数在同一时刻可以被多个线程安全地调用,就称改函数是线程安全的。
5.线程私有数据
#include <pthread.h> int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *)); |
Returns: 0 if OK, error number on failure |
#include <pthread.h>
int pthread_key_delete(pthread_key_t *key);
|
Returns: 0 if OK, error number on failure |
#include <pthread.h> pthread_once_t initflag = PTHREAD_ONCE_INIT; int pthread_once(pthread_once_t *initflag, void (*initfn)(void)); |
Returns: 0 if OK, error number on failure |
键和线程私有数据的关联
#include <pthread.h>
void *pthread_getspecific(pthread_key_t key);
|
Returns: thread-specific data value or NULL if no value |
int pthread_setspecific(pthread_key_t key, const void *value); |
Returns: 0 if OK, error number on failure |
6.取消选项
线程的可取消状态和可取消类型。这两个属性直接影响到pthread_cancel函数调用是呈现的行为
#include <pthread.h> int pthread_setcancelstate(int state, int *oldstate); |
Returns: 0 if OK, error number on failure |
自己添加取消点
#include <pthread.h> void pthread_testcancel(void); |
修改取消类型
#include <pthread.h> int pthread_setcanceltype(int type, int *oldtype); |
Returns: 0 if OK, error number on failure |
7. 线程和信号
#include <signal.h> int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset); |
Returns: 0 if OK, error number on failure |
#include <signal.h> int sigwait(const sigset_t *restrict set, int *restrict signop); |
Returns: 0 if OK, error number on failure |
#include <signal.h> int pthread_kill(pthread_t thread, int signo); |
Returns: 0 if OK, error number on failure |
例:同步信号处理
#include "apue.h" #include <pthread.h> int quitflag; /* set nonzero by thread */ sigset_t mask; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t wait = PTHREAD_COND_INITIALIZER; void * thr_fn(void *arg) { int err, signo; for (;;) { err = sigwait(&mask, &signo); if (err != 0) err_exit(err, "sigwait failed"); switch (signo) { case SIGINT: printf("\ninterrupt\n"); break; case SIGQUIT: pthread_mutex_lock(&lock); quitflag = 1; pthread_mutex_unlock(&lock); pthread_cond_signal(&wait); return(0); default: printf("unexpected signal %d\n", signo); exit(1); } } } int main(void) { int err; sigset_t oldmask; pthread_t tid; sigemptyset(&mask); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGQUIT); if ((err = pthread_sigmask(SIG_BLOCK, &mask, &oldmask)) != 0) err_exit(err, "SIG_BLOCK error"); err = pthread_create(&tid, NULL, thr_fn, 0); if (err != 0) err_exit(err, "can't create thread"); pthread_mutex_lock(&lock); while (quitflag == 0) pthread_cond_wait(&wait, &lock); pthread_mutex_unlock(&lock); /* SIGQUIT has been caught and is now blocked; do whatever */ quitflag = 0; /* reset signal mask which unblocks SIGQUIT */ if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) err_sys("SIG_SETMASK error"); exit(0); }
8.线程和fork
在子进程内部只存在一个线程,它是由父进程中调用fork的线程的副本构成
如果父进程包含多个线程,子进程在fork返回后,如果接着不是马上调用exec的话,就需要清理锁状态
#include <pthread.h> int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)); |
Returns: 0 if OK, error number on failure |
例:
#include "apue.h" #include <pthread.h> pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER; void prepare(void) { printf("preparing locks...\n"); pthread_mutex_lock(&lock1); pthread_mutex_lock(&lock2); } void parent(void) { printf("parent unlocking locks...\n"); pthread_mutex_unlock(&lock1); pthread_mutex_unlock(&lock2); } void child(void) { printf("child unlocking locks...\n"); pthread_mutex_unlock(&lock1); pthread_mutex_unlock(&lock2); } void * thr_fn(void *arg) { printf("thread started...\n"); pause(); return(0); } int main(void) { int err; pid_t pid; pthread_t tid; #if defined(BSD) || defined(MACOS) printf("pthread_atfork is unsupported\n"); #else if ((err = pthread_atfork(prepare, parent, child)) != 0) err_exit(err, "can't install fork handlers"); err = pthread_create(&tid, NULL, thr_fn, 0); if (err != 0) err_exit(err, "can't create thread"); sleep(2); printf("parent about to fork...\n"); if ((pid = fork()) < 0) err_quit("fork failed"); else if (pid == 0) /* child */ printf("child returned from fork\n"); else /* parent */ printf("parent returned from fork\n"); #endif exit(0); }
9.线程和IO
pread pwrite在多线程环境中非常有帮助