1. Each object is associated with its own type of attribute object (threads with thread attributes, mutexes with mutex attributes, and so on). An attribute object can represent multiple attributes. The attribute object is opaque to applications. This means that applications aren’t supposed to know anything about its internal structure, which promotes application portability .Instead, functions are provided to manage the attributes objects.
2. An initialization function exists to set the attributes to their default values.
3. Another function exists to destroy the attributes object. If the initialization function allocated any resources associated with the attributes object, the destroy function frees those resources.
4. Each attribute has a function to get the value of the attribute from the attribute object. Because the function returns 0 on success or an error number on failure, the value is returned to the caller by storing it in the memory location specified by one of the arguments.
5. Each attribute has a function to set the value of the attribute. In this case, the value is passed as an argument,by value.
#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
#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
重点还是理解一下pthread_attr_init 和pthread_attr_destroy吧。。。
#include <stdio.h> #include <pthread.h> void* thread_func(void*); int main() { int temp = 0; int err = 0; int return_val = 0; pid_t pid; pthread_t tid; pthread_attr_t attr; pid = getpid(); tid = pthread_self(); printf("current pid :%u\ncurrent thread %u\n",(unsigned int)pid,(unsigned int)tid); 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,NULL,thread_func,0); if(err != 0) { printf("can‘t creat thread\n"); } } err = pthread_join(tid,NULL); pthread_attr_destroy(&attr); return 0; } void* thread_func(void* smg) { printf("thread processing\n"); printf("current thread ID:%u\n",(unsigned int)pthread_self()); printf("current PID:%u\n",(unsigned int)getpid()); printf("thread end\n"); return (void*)1; }
#include <pthread.h> int pthread_attr_getstack(const pthread_attr_t *restrict attr , void **restrictstackaddr ,size_t *restrict stacksize ); int pthread_attr_setstack(pthread_attr_t *attr ,void *stackaddr ,size_tstacksize ); Both return: 0 if OK, error number on failure
Mute xAttributes
#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
The process-shared mutex attribute is set to PTHREAD_PROCESS_PRIVATE .
If the process-shared mutex attribute is set to PTHREAD_PROCESS_SHARED, a mutex allocated from a memory extent shared between multiple processes may be used for synchronization by those processes
#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
APUE这种神作我不知道为什么,作者还是会出纰漏。。。斗胆挑一下大神写的代码段毛病,变量不初始化,没有意识到垃圾值给力指针,并尝试使用该指针。
这种现象我好像是第二次看到了,作者也不给个测试,只是给了代码。
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)) { if(tip != NULL)
Reader–writer locks also have attributes, similar to mutexes. We use pthread_rwlockattr_init to initialize a pthread_rwlockattr_tstructure and pthread_rwlockattr_destroy to deinitialize the structure.
#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
If a function can be safely called by multiple threads at the same time, we say that the function is thread-safe .
If a function is reentrant with respect to multiple threads, we say that it is thread-safe.
Thread-Specific Data
why would anyone want to promote interfaces that prevent sharing in this model?
There are two reasons.
First, sometimes we need to maintain data on a per-thread basis.
The second reason for thread-private data is to provide a mechanism for adapting process-based interfaces to a multithreaded environment.
Beforeallocating thread-specific data, we need to create a key to associate with the
data. The key will be used to gain access to the thread-specific data. We use
pthread_key_create to create such a key.
#include <pthread.h> int pthread_key_create(pthread_key_t * keyp ,void (*destructor)(void *)); Returns: 0 if OK, error number on failure
If destructor is null, then no destructor function is associated with the key. When the thread exits normally,either by calling pthread_exitor by returning, the destructor is called. Also, if the thread
is canceled, the destructor is called, but only after the last cleanup handler returns. But if the thread calls exit, _exit, _Exit, or abort, or otherwise exits abnormally ,the destructor is not called.
We can break the association of a key with the thread-specific data values for all threads by calling pthread_key_delete .
#include <pthread.h> int pthread_key_delete(pthread_key_t key); Returns: 0 if OK, error number on failure
Note that calling pthread_key_delete will not invoke the destructor function associated with the key.To free any memory associated with the key’s thread-specific data values, we need to take additional steps in the
application.
pthread_key_creat 创建key的时候可能有不同进程竞争的现象
Depending on how the system schedules threads, some threads might see one key value, whereas other threads might see a different value. The way to solve this race to use pthread_once.
#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 has been associated with the key int pthread_setspecific(pthread_key_t key,const void *value); Returns: 0 if OK, error number on failure If no thread-specific data has been associated with a key, pthread_getspecific will return a null pointer.
Two thread attributes that are not included in the pthread_attr_t structure are t he cancelability state and the cancelability type.These attributes affect the behavior of a thread in response to a call
to pthread_cancel (Section 11.5). The cancelability state attribute can be either PTHREAD_CANCEL_ENABLE or
PTHREAD_CANCEL_DISABLE.A thread can change its cancelability state by calling pthread_setcancelstate.
#include <pthread.h> int pthread_setcancelstate(intstate ,int *oldstate); Returns: 0 if OK, error number on failure
When the state is set toPTHREAD_CANCEL_DISABLE,ac all to pthread_cancel will not kill the thread. Instead, the cancellation request remains pending for the thread
If your application doesn’t call one of the functions in Figure12.14 or Figur e12.15 for a long period of time (if it is compute bound, for example), then you can call pthread_testcancel to add your own cancellation points to the program.
#include <pthread.h> void pthread_testcancel(void);
we discussed how processes can use the sigprocmask function to block signals from delivery.However,t he behavior of sigprocmask is undefined in a multithreaded process. Threads have to use thepthread_sigmaskfunction instead.
#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
The sigwaitfunction will atomically unblock the signals and wait until one is delivered. Before returning, sigwait will restore the thread’s signal mask
The advantage to using sigwaitis that it can simplify signal handling by allowing us to treat asynchronously generated signals in a synchronous manner.
To send a signal to a process, we call kill (Section 10.9). To s end a signal to thread, we call pthread_kill.
#include <signal.h> int pthread_kill(pthread_t thread ,int signo); Returns: 0 if OK, error number on failure
、、、、、、、、、、、、、、、、、、
By inheriting a copy of the address space, the child also inherits the state of every mutex, reader–writer lock, and condition variable from the parent process. If the parent consists of more than
one thread, the child will need to clean up the lock state if it isn’t going to call exec immediately after fork re turns.
Inside the child process, only one thread exists. It is made from a copy of the thread that called fork in the parent. If the threads in the parent process hold any locks, the same locks will also be held in
the child process. The problem is that the child process doesn’t contain copies of the threads holding the locks, so there is no way for the child to know which locks are held and need to be unlocked.
To clean up the lock state, we can establish fork handlers by calling the function pthread_atfork.
#include <pthread.h> int pthread_atfork(void (*prepare )(void), void (*parent )(void), void (*child )(void)); Returns: 0 if OK, error number on failure
With pthread_atfork, we can install up to three functions to help clean up the locks. The prepare fork handler is called in the parent before fork creates the child process. This fork handler’s job is
to acquire all locks defined by the parent. The parent fork handler is called in the context of the parent after fork has created the child process, but before fork has returned. This fork handler’s job is to unlock all the locks acquired by
the prepare fork handler .The child fork handler is called in the context of the child process before returning from fork.Like the parent fork handler ,the child fork handler must release all the locks acquired by the prepare fork handler.
#include <stdio.h> #include <pthread.h> #include <signal.h> #include <stdlib.h> #include <myerr.h> int quitflag; 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\n"); } 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("exexpected signal %d\n",signo); exit(1); } } } } int main() { 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\n"); } err = pthread_create(&tid,NULL,thr_fn,0); if(err != 0) { err_exit(err,"can‘t create thread\n"); return 0; } err = pthread_create(&tid,NULL,thr_fn,0); if(err != 0) { err_exit(err,"can‘t create thread\n"); return 0; } pthread_mutex_lock(&lock); while(quitflag == 0) { pthread_cond_wait(&wait,&lock); } pthread_mutex_unlock(&lock); quitflag = 0; if(sigprocmask(SIG_SETMASK,&oldmask,NULL) <0) { err_sys("SIG_SETMASK error\n"); } exit(0); }
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_12$ ./a.out^C
interrupt
^C
interrupt
^C
interrupt
^\
By inheriting a copy of the address space, the child also inherits the state of every mutex, reader–writer lock, and condition variable from the parent process. If the parent consists of more than one thread,
the child will need to clean up the lock state if it isn’t going to call exec immediately after fork returns.
If the threads in the parent process hold any locks, the same locks will also be held in the child process. The problem is that the child process doesn’t contain copies of the threads holding the locks, so there is no
way for the child to know which locks are held and need to be unlocked.这点在讲fork的时候讲过
#include <pthread.h> int pthread_atfork(void (*prepare )(void), void (*parent )(void), void (*child )(void)); Returns: 0 if OK, error number on failure
With pthread_atfork, we can install up to three functions to help clean up the locks. The prepare fork handler is called in the parent before fork creates the child process. This fork handler’s job is
to acquire all locks defined by the parent. The parent fork handler is called in the context of the parent after fork has created the child process, but before fork has returned. This fork handler’s job is to unlock all the locks acquired by
the prepare fork handler .The child fork handler is called in the context of the child process before returning from fork.Like the parent fork handler ,the child fork handler must release all the locks acquired by the prepare fork handler。
demo:
#include <signal.h> #include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <myerr.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...\n"); pthread_mutex_unlock(&lock1); pthread_mutex_unlock(&lock2); } void* thr_fn(void* arg) { printf("thread started ...\n"); pause();//wait atfork to finish return (void*)1; } int main() { 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 for handlers"); } err = pthread_create(&tid,NULL,thr_fn,0); if(err != 0) { err_exit(err,"can‘t create thread\n"); } sleep(2); printf("parent about to fork...\n"); if((pid = fork()) < 0) { err_quit("fork failed\n"); } else if(pid == 0) { printf("child returned from fork\n"); } else { printf("parent returned from fork\n"); } #endif return 0; }
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_12$ ./a.out
thread started ...
parent about to fork...
preparing locks ...
parent unlocking locks ...
parent returned from fork
child unlocking...
child returned from fork
最近几天效率极其低下。。。
《APUE》chapter 12 Thread control 学习笔记(加上自己的代码),布布扣,bubuko.com
《APUE》chapter 12 Thread control 学习笔记(加上自己的代码)
原文:http://blog.csdn.net/cinmyheart/article/details/22929673