现在的位置: 首页 > 综合 > 正文

apue(9)

2012年09月15日 ⁄ 综合 ⁄ 共 9100字 ⁄ 字号 评论关闭

 

11.2. Thread Concepts

The feature test macro for POSIX threads is _POSIX_THREADS. Applications can either use this in an #ifdef test to determine at compile time whether threads are supported or call sysconf with the _SC_THREADS constant to determine at runtime whether threads are supported.

11.3. Thread Identification

#include <pthread.h> int pthread_equal(pthread_t tid1, pthread_t tid2); #include <pthread.h> pthread_t pthread_self(void);

11.4. Thread Creation

#include <pthread.h> int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void), void *restrict arg); 

The memory location pointed to by tidp is set to the thread ID of the newly created thread when pthread_create returns successfully. The attr argument is used to customize
various thread attributes. We'll cover thread attributes in
Section 12.3
, but for now, we'll set this to NULL to create a thread with the default attributes.

The newly created thread starts running at the address of the start_rtn function. This function takes a single argument, arg, which is a typeless pointer. If you need to pass more than one argument
to the start_rtn function, then you need to store them in a structure and pass the address of the structure in arg.

The set of pending signals for the thread is cleared. 因为errno是每个线程一个,所以这个函数的返回值不同于其他函数,错误直接返回错误号,正确返回0. 两点问题 The first is the need to sleep in the main thread. If it doesn't sleep, the main thread might exit, thereby terminating the entire process before the new thread gets a chance to run. 第二,新线程需要通过pthread_self来获取自己的thread ID,因为新线程可能在pthread_create返回之前就开始运行,所以tidp可能没有构造完成。 Man pthreadsMan clone Linux下的thread_create 可能先clone一个process分享textfd,然后执行线程。(?) 实际中,相同代码结果两个线程pid一致? main thread: pid 3657 tid 3079084848 (0xb7871b30)  new thread: pid 3657 tid 3079076720 (0xb786fb70)  linux下编译需要<pthread.h>的文件 需要加上编译选项-thread

11.5. Thread Termination

#include <pthread.h> void pthread_exit(void *rval_ptr);
  1. The thread can simply return from the start routine.
    The return value is the thread's exit code.

  2. The thread can be canceled by another thread in the same process.

  3. The thread can call
    pthread_exit.

#include <pthread.h> int pthread_join(pthread_t thread, void **rval_ptr); If the thread simply returned from its start routine, rval_ptr will contain the return code. If the thread was canceled, the memory location specified by rval_ptr is set to PTHREAD_CANCELED. By calling pthread_join, we automatically place a thread in the detached state (discussed shortly) so that its resources can be recovered. If the thread was already in the detached state, calling pthread_join fails, returning EINVAL. If we're not interested in a thread's return value, we can set rval_ptr to NULL. In this case, calling pthread_join allows us to wait for the specified thread, but does not retrieve the thread's termination status. pthread_exit((void *) 0)相当于return ((void*)0).线程的返回状态为0. pthread_join(tid,...)功能相当于waitpid,阻塞等到线程号为tid的线程调用pthread_exit()(return)结束,并指出返回状态为状态号或者PTHRAD_CANCELED 当真正使用rval_ptr指向一个结构体传参时,注意其不应该是一个临时变量,之后pthread_join会捕捉到它并使用。 #include <pthread.h> int pthread_cancel(pthread_t tid); 请求tid线程以PTHREAD_CANCELED为参执行pthread_exit(PTHREAD_CANCELED)。被请求进程可能不理会,或者以自己的方式结束 #include <pthread.h> void pthread_cleanup_push(void (*rtn)(void *), void *arg); void pthread_cleanup_pop(int execute); //参数为0时,不会其作用。否则,执行最后一个注册的函数 在一些实现中,可能会在pushpop以宏的形式实现中间分别加上了{},所以写法上必须成对,但可以参数为0不执行。 Thus, if the thread terminates by returning from its start routine, its cleanup handlers are not called. 注册的函数如果不是1 pthread_exit 2 pthread_cleanup_pop 3 其他线程cancel的话就不会执行。正常的return不会执行。 #include <pthread.h> int pthread_detach(pthread_t tid); //使tid线程detached wait一样,结束的线程会在一定的时间内保持一些信息。但detached后,信息会丢失,pthread_join会返回错误EINVAL

Process primitive

Thread primitive

Description

fork

pthread_create

create a new flow of control

exit

pthread_exit

exit from an existing flow of control

waitpid

pthread_join

get exit status from flow of control

atexit

pthread_cancel_push

register function to be called at exit from flow of control

getpid

pthread_self

get ID for flow of control

abort

pthread_cancel

request abnormal termination of flow of control

11.6. Thread Synchronization

Mutexes

#include <pthread.h> int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); int pthread_mutex_destroy(pthread_mutex_t *mutex); Before we can use a mutex variable, we must first initialize it by either setting it to the constant PTHREAD_MUTEX_INITIALIZER (for statically-allocated mutexes only) or calling pthread_mutex_init. If we allocate the mutex dynamically (by calling malloc, for example), then we need to call pthread_mutex_destroy before freeing the memory. 创建一个mutex varialble,我们要先声明一个指针 指向静态的PTHREAD_MUTEX_INITIALIZER或者调用pthread_mutex_t(ptr,NULL)为他申请一块儿空间,最后pthread_mutex_destroy(ptr)释放。 #include <pthread.h> int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); //成功会返回0并且lock,失败(已经被别人上锁了)返回EBUSY int pthread_mutex_unlock(pthread_mutex_t *mutex); 锁锁的一般是操作,保证lockunlock之间的操作不会被打扰。例, #include <stdlib.h> #include <pthread.h> struct foo { int f_count; pthread_mutex_t f_lock; /* ... more stuff here ... */ }; struct foo * foo_alloc(void) /* allocate the object */ { struct foo *fp; if ((fp = malloc(sizeof(struct foo))) != NULL) { fp->f_count = 1; if (pthread_mutex_init(&fp->f_lock, NULL) != 0) { free(fp); return(NULL); } /* ... continue initialization ... */ } return(fp); } void foo_hold(struct foo *fp) /* add a reference to the object */ { pthread_mutex_lock(&fp->f_lock); fp->f_count++; //这一步也可能在CPU上分为三步,读、改、写,多线程时可能有同步问题。 pthread_mutex_unlock(&fp->f_lock); } void foo_rele(struct foo *fp) /* release a reference to the object */ { pthread_mutex_lock(&fp->f_lock); if (--fp->f_count == 0) { /* last reference */ pthread_mutex_unlock(&fp->f_lock); pthread_mutex_destroy(&fp->f_lock); free(fp); } else { pthread_mutex_unlock(&fp->f_lock); } }

Deadlock Avoidance

You'll have the potential for a deadlock only when one thread attempts to lock the mutexes in the opposite order from another thread. You can use the pthread_mutex_trylock interface to avoid deadlocking in this case. If you are already holding locks and pthread_mutex_trylock is successful, then you can proceed. If it can't acquire the lock, however, you can release the locks you already hold, clean up, and try again later. 哈希函数用宏实现 #define NHASH 29 #define HASH(fp) (((unsigned long)fp)%NHASH) 基本思想是,多个锁时,编程时每一次都确保上锁的先后顺序。

ReaderWriter Locks

Three states are possible with a readerwriter lock: locked in read mode, locked in write mode, and unlocked. Only one thread at a time can hold a readerwriter lock in write mode, but multiple threads can hold a readerwriter lock in read mode at the same time. When a readerwriter lock is write-locked, all threads attempting to lock it block until it is unlocked. When a readerwriter lock is read-locked, all threads attempting to lock it in read mode are given access, but any threads attempting to lock it in write mode block until all the threads have relinquished their read locks.  Readerwriter locks are also called sharedexclusive locks. When a readerwriter lock is read-locked, it is said to be locked in shared mode. When it is write-locked, it is said to be locked in exclusive mode. #include <pthread.h> int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); attr一般为NULL #include <pthread.h> int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); 错误返回错误号 #include <pthread.h> int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); 

When the lock can be acquired, these functions return 0. Otherwise, they return the error
EBUSY.

Condition Variables(?)

#include <pthread.h> int pthread_cond_init(pthread_cond_t *restrict cond, pthread_condattr_t *restrict attr); int pthread_cond_destroy(pthread_cond_t *cond); #include <pthread.h> int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict timeout); We use pthread_cond_wait to wait for a condition to be true. A variant is provided to return an error code if the condition hasn't been satisfied in the specified amount of time. struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; 使用的是real time,现在时间加上需要的时间,一般技巧如下 void maketimeout(struct timespec *tsp, long minutes) { struct timeval now; /* get the current time */ gettimeofday(&now); tsp->tv_sec = now.tv_sec; tsp->tv_nsec = now.tv_usec * 1000; /* usec to nsec */ /* add the offset to get timeout value */ tsp->tv_sec += minutes * 60; } If the timeout expires without the condition occurring, pthread_cond_timedwait will reacquire the mutex and return the error ETIMEDOUT. When it returns from a successful call to pthread_cond_wait or pthread_cond_timedwait, a thread needs to reevaluate the condition, since another thread might have run and already changed the condition. The mutex passed to pthread_cond_wait protects the condition. The caller passes it locked to the function, which then atomically places the calling thread on the list of threads waiting for the condition and unlocks the mutex. This closes the window between the time that the condition is checked and the time that the thread goes to sleep waiting for the condition to change, so that the thread doesn't miss a change in the condition. When pthread_cond_wait returns, the mutex is again locked. mutex被传递给pthread_cond_wait来保护条件。调用者把上锁的metux传给函数,函数然后原子的将调用线程放在等待该条件的队列、解锁mutex。这减少了条件被检测和程序进入等待的间隔时间,使得线程不会错过条件的改变。当函数返回时,mutex又是上锁的。 #include <pthread.h> int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); There are two functions to notify threads that a condition has been satisfied. The pthread_cond_signal function will wake up one thread waiting on a condition, whereas the pthread_cond_broadcast function will wake up all threads waiting on a condition. a thundering herd problem, whereby many threads are awakened without work to do, resulting in a waste of CPU resources and increased lock contention.

抱歉!评论已关闭.