线程的知识点
1,线程的创建 pthread_create()
2,线程的退出 pthread_exit()
3,线程的退出后 返回值怎么获得 pthread_join()
4,主动取消一个线程 pthread_cancel()
5,当被 别人取消时, 还能做点什么(安排后事),处理取消函数
pthread_cleanup_push()
phread_cleanup_pop()
线程同步
6, pthread_mutex_init()
7, pthread_mutex_lock()
8, pthread_mutex_unlock()
9, pthread_mutex_destroy()

读写锁
10,pthread_rwlock_init()
11 , pthread_rwlock_destroy()
12 , pthread_rwlock_rdlock()
13 , pthread_rwlock_wrlock()
14 , pthread_rwlock_unlock()
15 , pthread_rwlock_tryrdlock()
16 , pthread_rwlock_trywrlock()
当读的频率远高于写的频率时, 使用读写锁才能 提高性能。

17, pthread_cond_init()
18, pthread_cond_destroy()

19, pthread_cond_wait()
20, pthread_cond_timedwait()
21, pthread_cond_singal()
22, pthread_cond_broadcast()

线程控制

线程属性 pthread_attr_t
创建线程时,可以以默认线程启动,也可以修改属性。
pthread_attr_init()
pthread_attr_destroy()

该线程属性,在创建线程的时候设置,包括具体三方面的属性
01分离状态属性
pthread_attr_getdetachstate()
pthread_attr_setdetachstate()
PTHREAD_CREATE_DETACHED
PTHREAD_CREATE_JOINABLE

02线程栈
pthread_attr_getstack()
pthread_attr_setstack()
pthread_attr_getstacksize()
pthread_attr_setstacksize()
前两个要处理 线程栈的分配问题 , 后两个可以 改变默认线程栈的大小,而避免处理线程栈的分配。

03警戒缓冲区
pthread_attr_getguardsize()
pthread_attr_setguardsize()

还有一些属性并没有在pthread_attr_t 结构中表达,包括三个
01 可取消状态
02 可取消类型
03 并发度

并发度
pthread_getconcurrency(void)
pthread_setconcurrency(int level) 提示系统并发度。
0表示 系统控制着并发度。

同步属性
互斥量属性– 之前创建的互斥量用的是默认属性,这里可以设置。
pthread_mutexattr_init()
pthread_mutexattr_destroy()
互斥量的属性包括,
1,进程共享属性 ,表明这个互斥量 时候能被别的进程使用。
pthread_mutexattr_getpshared()
pthread_mutexattr_setpshared()
PTHREAD_PROCESS_PRIVATE
PTHREAD_PROCESS_SHARED

2,类型 ,互斥量有4中类型, 其实是3中类型 ,第四种是默认类型。
PTHREAD_MUTEX_NORMAL 普通互斥量
PTHREAD_MUTEX_ERRORCHECK 检查死锁
PTHREAD_MUTEX_RECURSIVE 可多次加锁,需多次解锁
PTHREAD_MUTEX_DEFAULT

如何获取互斥量的类型
pthread_mutexattr_gettype()
pthread_mutexattr_settype()
递归互斥量 不建议使用。

读写锁属性
pthread_rwlockattr_init()
pthread_rwlockattr_destroy()
进程共享属性 读写锁只有这一个属性, 关于是否在进程间共享。
pthread_rwlockattr_getpshared()
pthread_rwlockattr_setpshared()

条件变量的属性
pthread_condattr_init()
pthread_condattr_destory()
条件变量的唯一属性 也是 共享进程属性。
pthread_condattr_getpshared()
pthread_condattr_setpshared()

ftrylockfile()
flockfile()
funlockfile()

线程私有数据
创建与私有数据相关的键 pthread_key_create() 参数中,第二个是析构函数
pthread_key_delete() 取消键与 线程私有数据之间的关系。这个并不会调用析构函数,还要自己调用。

pthread_once_t initflag = PTHREAD_ONCE_INIT initflag必须是非本地变量,即是 静态变量或者是全局变量 。
pthread_once(pthread_once_t * initflag, void (*initfn) (void));

每个线程都调用pthread_once 系统就能保证,初始化例程 initfn只被调用一次。

键创建之后,就可以 把键和线程私有数据关联起来了。
pthread_getspecific()
pthread_setspecific()

取消选项
pthread_setcancelstate()
可取消状态可以是 PTHREAD_CANCEL_ENABLE
PTHREAD_CANCEL_DISABLE

线程在 取消点 才检查是否被取消。
线程的 默认状态是 可取消状态。

注意

  1. 当线程被分离时,不能用pthread_join()来获取它的最终状态。
  2. 当有两个互斥量, 而两个线程 以相反的顺序去 锁住这两个互斥量时, 就可能发生死锁。 解决办法是: 所有的线程,以相同的顺序,来锁住 互斥量。 就可以避免死锁。
  3. 加锁不是为了让程序更复杂,而是要解决,线程访问共享资源的问题。
  4. 如果一个函数,在同一时刻,可以被多个线程,安全地调用,,就称该函数是 线程安全 的。
  5. _r 表明这个版本是 可重入的。 也就是线程安全的。
  6. 对多线程可重入,并不说明对 信号处理程序来说也是安全的。

Q&A

  1. 直接gcc编译,ld出错。 [root@ apue]# gcc pthread_test1.c /tmp/ccCYsvBg.o:
    In function ​​main': pthread_test1.c:(.text+0x8a): undefined
    reference to​
    ​pthread_create’ collect2: ld 返回 1
    gcc编译,加上pthread库 -lpthread, 编译成功。 [root@ST apue]# gcc
    pthread_test1.c -lpthread
    运行 [root@ST apue]# ./a.out main thread: pid 23484 tid 3298916096
    (c4a17700) new thread : pid 23484 tid 3298907904 (c4a15700)
    编译使用线程的程序 ,需要链接上线程的库 -lpthread 。