第十二章 线程控制:
#include <pthread.h>
int pthread_attr_init(pthread_attr_t * attr);
if success return 0, else return error-no, will not modify errno
int pthread_attr_destroy(pthread_attr_t * attr);
if success return 0, else return error-no, will not modify errno
#include <pthread.h>
int pthread_attr_getdetachstate(const pthread_attr_t * restrict attr,
int * detachstate);
if success return 0, else return error-no, will not modify errno
int pthread_attr_setdetachstate(pthread_attr_t * attr, int detachstate);
if success return 0, else return error-no, will not modify errno
detachstate:
PTHREAD_CREATE_DETACHED
PTHREAD_CREATE_JOINABLE
#include <pthread.h>
int pthread_attr_getstack(const pthread_attr_t * restrict attr,
void ** restrict stackaddr,
size_t * restrict stacksize);
if success return 0, else return error-no, will not modify errno
int pthread_attr_setstack(pthread_attr_t * attr,
void * stackaddr, size_t stacksize);
if success return 0, else return error-no, will not modify errno
#include <pthread.h>
int pthread_attr_getstacksize(const pthread_attr_t * restrict attr,
size_t * restrict stacksize);
if success return 0, else return error-no, will not modify errno
int pthread_attr_setstacksize(pthread_attr_t * attr, size_t stacksize);
if success return 0, else return error-no, will not modify errno
#include <pthread.h>
int pthread_attr_getguardsize(const pthread_attr_t * restrict attr,
size_t * restrict guardsize);
if success return 0, else return error-no, will not modify errno
int pthread_attr_setguardsize(pthread_attr_t * attr, size_t guardsize);
if success return 0, else return error-no, will not modify errno
#include <pthread.h>
int pthread_getconcurrency(void);
return current concurrency, 0 means system default
int pthread_setconcurrency(int level);
if success return 0, else return error-no, will not modify errno1
#include <pthread.h>
int pthread_mutexattr_init(pthread_mutexattr_t * attr);
if success return 0, else return error-no, will not modify errno
int pthread_mutexattr_destroy(pthread_mutexattr_t * attr);
if success return 0, else return error-no, will not modify errno
#include <pthread.h>
int pthread_mutexattr_getpshared(const pthread_mutexattr_t * restrict attr,
int * restrict pshared);
if success return 0, else return error-no, will not modify errno
int pthread_mutexattr_setpshared(pthread_mutexattr_t * attr, int pshared);
if success return 0, else return error-no, will not modify errno
pshared:
PTHREAD_PROCESS_PRIVATE /* for multi-thread */
PTHREAD_PROCESS_SHARED /* for multi-process */
#include <pthread.h>
int pthread_mutexattr_gettype(const pthread_mutexattr_t * restrict attr,
int * restrict type);
if success return 0, else return error-no, will not modify errno
int pthread_mutexattr_settype(pthread_mutexattr_t * attr, int type);
if success return 0, else return error-no, will not modify errno
type:
PTHREAD_MUTEX_NORMAL
PTHREAD_MUTEX_ERRORCHECK
PTHREAD_MUTEX_RECURSIVE
PTHREAD_MUTEX_DEFAULT
#include <pthread.h>
int pthread_rwlockattr_init(pthread_rwlockattr_t * attr);
if success return 0, else return error-no, will not modify errno
int pthread_rwlockattr_destroy(pthread_rwlockattr_t * attr);
if success return 0, else return error-no, will not modify errno
#include <pthread.h>
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t * restrict attr,
int * restrict pshared);
if success return 0, else return error-no, will not modify errno
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t * attr, int pshared);
if success return 0, else return error-no, will not modify errno
pshared:
PTHREAD_PROCESS_PRIVATE /* for multi-thread */
PTHREAD_PROCESS_SHARED /* for multi-process */
#include <pthread.h>
int pthread_condattr_init(pthread_condattr_t * attr);
if success return 0, else return error-no, will not modify errno
int pthread_condattr_destroy(pthread_condattr_t * attr);
if success return 0, else return error-no, will not modify errno
#include <pthread.h>
int pthread_condattr_getpshared(const pthread_condattr_t * restrict attr,
int * restrict pshared);
if success return 0, else return error-no, will not modify errno
int pthread_condattr_setpshared(pthread_condattr_t * attr, int pshared);
if success return 0, else return error-no, will not modify errno
pshared:
PTHREAD_PROCESS_PRIVATE /* for multi-thread */
PTHREAD_PROCESS_SHARED /* for multi-process */
#include <stdio.h>
int ftrylockfile(FILE * fp);
if success return 0, else return non-zero
void flockfile(FILE * fp);
void funlockfile(FILE * fp);
#include <stdio.h>
int getchar_unlock(void);
if error or end-of-file return EOF, if EOF check it with ferror or feof
int getc_unlock(FILE * fp);
if error or end-of-file return EOF, if EOF check it with ferror or feof
int putchar_unlock(int c);
if success return c, else return EOF
int putc_unlock(int c, FILE * fp);
if success return c, else return EOF
#include <pthread.h>
int pthread_key_create(pthread_key_t * key, void (*destructor)(void *));
if success return 0, else return error-no, will not modify errno
#include <pthread.h>
int pthread_key_delete(pthread_key_t * key);
if success return 0, else return error-no, will not modify errno
#include <pthread.h>
pthread_once_t initflag = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t * initflag, void (*initfn)(void));
if success return 0, else return error-no, will not modify errno
#include <pthread.h>
void * pthread_getspecific(pthread_key_t key);
return thread private data, if no data match with key return NULL
int pthread_setspecific(pthread_key_t key, const void * value);
if success return 0, else return error-no, will not modify errno
#include <pthread.h>
int pthread_setcancelstate(int state, int * oldstate);
if success return 0, else return error-no, will not modify errno
state:
PTHREAD_CANCEL_ENABLE
PTHREAD_CANCEL_DISABLE
#include <pthread.h>
void pthread_testcancel(void);
#include <pthread.h>
int pthread_setcanceltype(int type, int * oldtype);
if success return 0, else return error-no, will not modify errno
type:
PTHREAD_CANCEL_DEFERRED /* default */
PTHREAD_CANCEL_ASYNCHRONOUS
#include <signal.h>
int pthread_sigmask(int how, const sigset_t * restrict set,
sigset_t * restrict oset);
if success return 0, else return error-no, will not modify errno
#include <signal.h>
int sigwait(const sigset_t * restrict set, int * restrict signop);
if success return 0, else return error-no, will not modify errno
#include <signal.h>
int pthread_kill(pthread_t thread, int signo);
if success return 0, else return error-no, will not modify errno
#include <pthread.h>
int pthread_atfork(void (*prepare)(void),
void (*parent)(void),
void (*child)(void));
if success return 0, else return error-no, will not modify errno
示例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>
struct to_info {
void (*to_fn)(void *); /* function */
void * to_arg; /* argument */
struct timespec to_wait; /* time to wait */
};
int
makethread(void * (*fn)(void *), void * arg, int detach)
{
int err;
int detachstate;
pthread_t tid;
pthread_attr_t attr;
if ((err = pthread_attr_init(&attr)) != 0) {
return(err);
}
if (detach != 0) {
detachstate = PTHREAD_CREATE_DETACHED;
}
else {
detachstate = PTHREAD_CREATE_JOINABLE;
}
err = pthread_attr_setdetachstate(&attr, detachstate);
if (err == 0) {
err = pthread_create(&tid, &attr, fn, arg);
}
pthread_attr_destroy(&attr);
return(err);
}
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);
free(arg);
return((void *)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 * 1000;
if ((when->tv_sec > now.tv_sec) ||
(when->tv_sec == now.tv_sec && when->tv_nsec > now.tv_nsec)) {
tip = (struct to_info *)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 = 1000000000 - now.tv_nsec + when->tv_nsec;
}
err = makethread(timeout_helper, tip, 1);
if (err == 0) {
return;
}
else {
free(tip);
}
}
}
(*func)(arg);
}
pthread_mutexattr_t attr;
pthread_mutex_t mutex;
void
retry(void * arg)
{
pthread_mutex_lock(&mutex);
/* ... perform retry steps ... */
printf("it is a test\n");
pthread_mutex_unlock(&mutex);
}
void
maketimespec(struct timespec * tsp, long seconds)
{
struct timeval now;
gettimeofday(&now, NULL);
tsp->tv_sec = now.tv_sec;
tsp->tv_nsec = now.tv_usec * 1000;
tsp->tv_sec += seconds;
}
int
main(void)
{
int err;
int condition;
int arg;
struct timespec when;
if ((err = pthread_mutexattr_init(&attr)) != 0) {
printf("pthread_mutexattr_init failed\n");
return(1);
}
err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
if (err != 0) {
printf("pthread_mutexattr_settype failed\n");
}
else if ((err = pthread_mutex_init(&mutex, &attr)) != 0) {
printf("pthread_mutex_init failed\n");
}
pthread_mutexattr_destroy(&attr);
if (err != 0) {
return(1);
}
/* ... */
pthread_mutex_lock(&mutex);
condition = 1;
if (condition) {
/* calculate target time "when" */
maketimespec(&when, 5);
timeout(&when, retry, (void *)arg);
}
/* ... */
pthread_mutex_unlock(&mutex);
/* ... */
sleep(10); /* wait */
exit(0); /* fflush */
}
#include <limits.h>
#include <string.h>
#define ARG_MAX (256)
char envbuf[ARG_MAX];
extern char ** environ;
char *
getenv(const char * name)
{
int i;
int len;
len = strlen(name);
for (i = 0; environ[i] != NULL; ++i) {
if ((strncmp(name, environ[i], len) == 0) &&
(environ[i][len] = '=')) {
strcpy(envbuf, &environ[i][len + 1]);
return(envbuf);
}
}
return(NULL);
}
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
extern char ** environ;
pthread_mutex_t env_mutex;
pthread_once_t init_done = PTHREAD_ONCE_INIT;
void
thread_init(void)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&env_mutex, &attr);
pthread_mutexattr_destroy(&attr);
}
int
getenv_r(const char * name, char * buf, int buflen)
{
int i;
int len;
int olen;
pthread_once(&init_done, thread_init);
len = strlen(name);
pthread_mutex_lock(&env_mutex);
for (i = 0; environ[i] != NULL; ++i) {
if ((strncmp(name, environ[i], len) == 0) &&
(environ[i][len] == '=')) {
olen = strlen(&environ[i][len + 1]);
if (olen >= buflen) {
pthread_mutex_unlock(&env_mutex);
return(ENOSPC);
}
else {
strcpy(buf, &environ[i][len + 1]);
pthread_mutex_unlock(&env_mutex);
return(0);
}
}
}
pthread_mutex_unlock(&env_mutex);
return(ENOENT);
}
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <pthread.h>
#define ARG_MAX (256)
pthread_key_t key;
pthread_once_t init_done = PTHREAD_ONCE_INIT;
pthread_mutex_t env_mutex = PTHREAD_MUTEX_INITIALIZER;
extern char ** environ;
void
thread_init(void)
{
pthread_key_create(&key, free);
}
char *
getenv(const char * name)
{
int i;
int len;
char * envbuf;
pthread_once(&init_done, thread_init);
pthread_mutex_lock(&env_mutex);
envbuf = (char *)pthread_getspecific(key);
if (envbuf == NULL) {
envbuf = (char *)malloc(ARG_MAX);
if (envbuf == NULL) {
pthread_mutex_unlock(&env_mutex);
return(NULL);
}
pthread_setspecific(key, envbuf);
}
len = strlen(name);
for (i = 0; environ[i] != NULL; ++i) {
if ((strncmp(name, environ[i], len) == 0) &&
(environ[i][len] == '=')) {
strcpy(envbuf, &environ[i][len + 1]);
pthread_mutex_unlock(&env_mutex);
return(envbuf);
}
}
pthread_mutex_unlock(&env_mutex);
return(NULL);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.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;
int signo;
for (;;) {
err = sigwait(&mask, &signo);
if (err != 0) {
printf("sigwait failed: %s\n", strerror(err));
exit(1);
}
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(NULL);
}
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) {
printf("pthread_sigmask(SIG_BLOCK) failed\n");
exit(1);
}
if ((err = pthread_create(&tid, NULL, thr_fn, NULL)) != 0) {
printf("pthread_create failed\n");
exit(1);
}
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) {
printf("sigprocmask(SIG_SETMASK) failed\n");
exit(1);
}
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.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) {
printf("cannot install fork handlers: %s\n", strerror(err));
exit(1);
}
if ((err = pthread_create(&tid, NULL, thr_fn, NULL)) != 0) {
printf("pthread_create failed: %s\n", strerror(err));
}
sleep(2);
printf("parent about to fork ...\n");
if ((pid = fork()) < 0) {
printf("fork failed\n");
exit(1);
}
else if (pid == 0) {
printf("child returned from fork\n");
}
else {
printf("parent returned from fork\n");
}
#endif
exit(0);
}
#include <unistd.h>
#include <time.h>
#include <sys/select.h>
unsigned int
sleep(unsigned int seconds)
{
int n;
unsigned slept;
time_t start;
time_t end;
struct timeval tv;
tv.tv_sec = seconds;
tv.tv_usec = 0;
time(&start);
n = select(0, NULL, NULL, NULL, &tv);
if (n == 0) {
return(0);
}
time(&end);
slept = end - start;
if (slept >= seconds) {
return(0);
}
else {
return(seconds - slept);
}
}