Unix——线程和线程控制

注:写得非常乱,以后有空再整理(在我们业界称为重构),没空就这样放着吧。



线程包含了表示进程内执行环境的必须信息。其中包括进程中的线程ID,一组寄存器值,栈,调度优先级和策略,
信号屏蔽字,errno变量,线程私有数据。进程所有信息对该进程的所有线程都是共享的包括,可执行的程序文本,
程序全局内存和堆内存,栈,文件描述符。
线程接口-POSIX.1-2001,"pthread","POSIX线程"


#include <pthread.h>
int pthread_equal(pthread_t id1, pthread_t id2);//相等返回非0;否则返回0

#include <pthread.h>
pthread_t pthread_self(void);//获得自身线程ID,参见getpid()


#include <pthread.h>
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 <pthread.h>
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 <pthread.h>
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 <pthread.h>
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 <pthread.h>
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_NORMAL,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不能保证是线程安全的函数,系统提供他们的线程安全版本


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值