Unix——线程和线程控制
线程包含了表示进程内执行环境的必须信息。其中包括进程中的线程ID,一组寄存器值,栈,调度优先级和策略,
信
注:写得非常乱,以后有空再整理(在我们业界称为重构),没空就这样放着吧。 线程包含了表示进程内执行环境的必须信息。其中包括进程中的线程ID,一组寄存器值,栈,调度优先级和策略, 信号屏蔽字,errno变量,线程私有数据。进程所有信息对该进程的所有线程都是共享的包括,可执行的程序文本, 程序全局内存和堆内存,栈,文件描述符。 线程接口-POSIX.1-2001,"pthread","POSIX线程" #include int pthread_equal(pthread_t id1, pthread_t id2);//相等返回非0;否则返回0 #include pthread_t pthread_self(void);//获得自身线程ID,参见getpid() #include int pthread_create(pthread_t *restrict id, const pthread_attr_t *restrict attr,//线程属性NULL void *(*fun)(void *), void *restrict arg);//新线程入口,函数fun, //如果函数参数有多个,则把这些参数放到一个结构中,然后把这个结构地址传入。 成功返回0,每个线程都提供errno的副本 C语言题外话:volatile和restrict 方便编译器优化, restrict,C99引入,只可以用于限定指针,并表明指针是访问一个数据对象的唯一且初始的方式; 指向的内容改变,则只能通过指针进行存取。 volatile告诉编译器该变量除了可被程序修改以外还可能被其他代理修改,因此,当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,而不是使用寄存器中的缓存。 线程退出: 1)线程从启动历程中返回,返回值是线程退出码。 2)线程可以被统一进程中的其它线程取消。 3)pthread_exit(void *rval_ptr); 线程被取消rval_ptr指向单元置为PTHREAD_CANCELED int pthread_join(pthread_t thread, void **rval_ptr); //调用线程阻塞,直到指定的线程调用pthread_exit,从启动例程中返回或者被取消 自动使线程处于分离状态。 int pthread_cancel(pthread_t tid);//提出请求取消同一进程中的其他线程,不等待线程终止。 线程清理处理程序 void pthread_cleanup_push(void (*fun)(void *), void *arg);--注册清理函数fun void pthread_cleanup_pop(int execute);--execute!=0执行清理,后注册先执行。 清理函数的调用顺序由pthread_cleanup_push函数来安排,线程执行以下动作时调用清理函数: 1)调用pthread_exit 2)响应取消请求时 3)用非零execute调用pthread_cleanup_pop时 int pthread_detach(pthread_t tid);使线程进入分离状态。 线程的状态:分离状态 线程的同步问题(互斥量,读写锁,条件变量) 互斥量 #include int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);//默认attr=NULL int pthread_mutex_destroy(pthread_mutex_t *mutex);//成功返回0 int pthread_mutex_lock(pthread_mutex_t *mutex);//加锁,互斥量已经上锁则线程阻塞,直到该互斥量解锁。 int pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁 int pthread_mutex_trylock(pthread_mutex_t *mutex);//尝试加锁,不阻塞。已加锁,返回EBUSY 避免死锁:两个线程同时请求两一个线程拥有的资源,从而产生死锁。 产生死锁的必要条件: 1)互斥 2)占有并等待 3)非抢先 4)循环等待 读写锁(共享独占锁),允许更高的并行性(三种状态,读模式下加锁,写模式下加锁,不加锁状态) 读写锁同互斥锁一样,在使用前初始化,在释放底层内存时必须销毁。 int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlock_t *restrict attr); int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);//读模式加锁 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);//写模式加锁 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);//解锁 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);//可以获取锁,返回0;否则返回EBUSY int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); 条件变量: #include int pthread_cond_init(pthread_cond_t *restrict cond, pthread_cond_t *restrict attr); int pthread_cond_destroy(pthread_cond_t *cond); 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); int pthread_cond_signal(pthread_cond_t *cond);//向线程或条件发送信号 int pthread_cond_broadcast(pthread_cond_t *cond); 线程限制(略) 线程属性 struct pthread_attr_t{};该结构不透明 #include int pthread_attr_init(pthread_attr_t *attr); int pthread_attr_destroy(pthread_attr_t *attr); detachstate 线程分离状态属性 guardsize 线程栈末尾的警戒缓冲区大小(字节数) stackaddr 线程栈的最低地址 stacksize 线程栈的大小(字节数) 若对某个线程的终止状态不感兴趣,调用int pthread_detach(pthread_t id)函数, 让OS在线程退出时,回收它所占用的资源。 分离状态属性: int pthread_attr_getdetachstate(const pthread_attr_t *restrict attr, int *detachstate); 创建线程,以分离状态启动 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); detachstate=PTHREAD_CANCEL_DETACHE PTHREAD_CREATE_JOINABLE(默认) 线程栈大小属性和线程栈最低地址: int pthread_attr_getstack(const pthread_attr_t *restrict attr, void **restrict stackaddr, size_t *restrict stacksize); int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t *stacksize) 线程栈大小属性 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); guardsize属性,控制着线程末尾之后用以避免栈溢出的扩展内存的大小。默认PAGESIZE 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); 有两个没有包含在pthread_attr_t结构中的属性——可取消状态和可取消类型,他们影响着pthread_cancel函数 调用时所呈现的行为。 可取消状态:PTHREAD_CANCEL_ENABLE默认,PTHREAD_CANCLE_DISABLE #include int pthread_setcancelstate(int state, int *oldstate); void pthread_testcancel(void);//手动添加取消点。 可取消类型:PTHREAD_CANCEL_DEFERRED延迟取消,PTHREAD_CANCEL_ASYNCHRONOUS异步取消,任意时间取消 int pthread_setcanceltype(int type, int *oldtype); 同步属性 互斥量属性pthread_mutexattr_t int pthread_mutexattr_init(pthread_mutexattr_t *mutexattr); int pthread_mutexattr_destroy(pthread_mutexattr_t *mutexattr); 进程共享互斥量属性:PTHREAD_PROCESS_SHARED,PTHREAD_PROCESS_PRIVATE(default) int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr, int *restrict pshared); int pthread-mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared); 类型互斥量属性:PTHREAD_MUTEX_NORMALunix线程切换,PTHREAD_MUTEX_ERRORCHECK, PTHREAD_MUTEX_RECURSIVE使之等同于信号量的功能.递归锁。 PTHREAD_MUTEX_DEFAULT,系统将其映射到其它类型 int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr, int *restrict type); int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type); 读写锁属性pthread_rwlockattr_t 读写锁的唯一属性是进程共享属性,参见互斥量。 条件变量属性pthread_condattr_t 也支持进程共享属性 重入问题,有了信号处理程序和线程,多个控制线程在同一时间可能潜在的调用同一个函数。 如果一个函数在同一时刻可以被多个线程安全的调用,则该函数是线程安全的。 如果一个函数对多个线程来说是可重入的,则这个函数是线程安全的,但并不说明对信号处理程序来说该函数也是可重入的。 若果函数对异步信号处理程序的重入是安全的,那么就可以说函数是异步信号安全函数。 线程安全函数(线程可重入的)和异步信号安全函数(信号处理程序可重入的) POSIX.1不能保证是线程安全的函数,系统提供他们的线程安全版本 (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |