APUE 学习笔记——线程控制

1、POSIX.1 定义的线程属性有哪些?

  • detachstate:线程的分离状态属性

    分离线程:这种类型的线程在退出时会由操作系统马上收回它所占有的资源。非分离线程在退出时会持有某些资源直到另一个线程对它调用pthread_join

  • guardsize:线程栈末尾的警戒缓冲区大小(字节数)

    一个线程的guardsize属性就是线程栈末尾的警戒缓冲区大小(字节数)。它控制着线程栈末尾之后,用以避免栈溢出的扩展内存大小。

  • stackaddr:线程栈的最低地址
  • stacksize:线程栈的最小长度(字节数)

    对于进程来说,虚拟地址空间的大小是固定的。因为进程中只有一个进程栈,因此其大小通常不是问题。但是对线程来说,同样大小的虚拟地址空间被所有的线程所共享。如果有很多个线程,以至于这些线程栈的总大小超过了可用的虚拟地址空间,则需要减少默认的线程栈大小。

    另外如果线程调用的函数分配了大量的自动变量,或者调用的函数设计很多很深的栈帧,则需要的线程栈大小可能要比默认的大。

    如果线程栈的虚拟地址空间都用完了,那么可以调用malloc或者mmap来为线程栈分配空间,并用pthread_attr_setstack函数来改变新建线程的线程栈的位置。

2、互斥量的属性有哪些?

  • 进程共享属性:决定了该互斥量是进程共享PTHREAD_PROCESS_SHARED,还是线程共享PTHREAD_PROCESS_PRIVATE
  • 健壮属性:它改变了当持有互斥量的进程未释放互斥量就退出时,另一个进程的线程调用pthread_mutex_lock的返回类型

    • PTHREAD_MUTEX_STALLED:意味着持有互斥量的进程终止时不需要采取特别的动作(即不需要释放互斥量),此时所有等待该互斥量的进程都将死锁。
    • PTHREAD_MUTEX_ROBUST:意味着持有互斥量的进程A终止时,如果进程A并没有释放互斥量,那么进程B的线程调用pthread_mutex_lock时,成功返回,且返回值为EOWNERDEAD(而不是死锁),但是进程B并不会持有锁(此时锁的状态被破坏了,因为锁的持有者死亡了,比必须调用下面的pthred_mutex_consistent函数来完修复锁的状态)。
  • 类型属性:控制了互斥量的锁定属性

    • PTHREAD_MUTEX_NORMAL:一种标准互斥量类型,不做任何特殊的错误检查或死锁检查
    • PTHREAD_MUTEX_ERRORCHECK:此类型互斥量进行错误检查
    • PTHREAD_MUTEX_RECURSIVE:此类型互斥量运行同一线程在互斥量解锁之前对该互斥量进行多次加锁(维持了一个加锁的计数)。当解锁次数和加锁次数不相同的情况下,并不会释放锁
    • PTHREAD_MUTEX_DEFAULT:此类型互斥量提供默认特性和行为。操作系统在实现的时候可以将它映射到上面三类中的任何一种。

3、读写锁的属性有哪些?

读写锁支持的唯一属性是进程共享属性。

4、条件变量属性有哪些?

  • 进程共享属性:条件变量的进程共享属性与互斥量的进程共享属性是相同的。
  • 时钟属性:控制了计算pthread_cond_timedwait函数的超时参数tsptr时,采用的是哪个时钟

    • CLOCK_REALTIME:实时系统时间
    • CLOCK_MONOTONIC:不带负跳数的实时系统时间
    • CLOCK_PROCESS_CPUTIME_ID:调用进程的CPU时间
    • CLOCK_THREAD_CPUTIME_ID:调用线程的CPU时间

5、屏障属性有哪些?

屏障支持的唯一属性是进程共享属性。

6、什么是线程特定数据?为什么需要线程特定数据?

线程特定数据也称作线程私有数据,是存储和查询某个线程相关数据的一种机制。我们采用线程特定数据的原因是:我们希望每个线程都可以访问线程各自独立的数据副本,而不需要担心与其他线程的同步问题。因为:

  • 有时候需要维护基于线程的数据
  • 线程特定数据让基于进程的接口适应于多线程环境。比如errno:为了让线程中可以使用原本基于进程的系统调用和库例程,errno被重新定义为线程私有数据。这样一个线程中做了重置errno的操作也不会影响进程中其它线程的errno

7、线程的可取消状态和可取消类型是什么?

可取消状态:

  • 线程B启动的默认的可取消状态是PTHREAD_CANCEL_ENABLE。此时,一旦线程B到达取消点时,线程B会执行取消操作。

  • 如果线程B的可取消状态设置为PTHREAD_CANCEL_DISABLE,则对线程B调用pthread_cancel并不会杀死线程。相反,对线程B来说,取消请求还是处于挂起的状态。当线程B的可取消状态再次变成PTHREAD_CANCEL_ENABLE时,线程B将在下一个取消点上对所有的挂起的取消请求进行处理。

可取消类型:

  • PTHREA_CANCEL_DEFERRED:延迟取消
  • PTHREAD_CANCEL_ASYNCHRONOUS: 异步取消。此时线程可以在任意时间取消,不是非的遇到取消点才能被取消

8、在多线程的环境下信号屏蔽字和信号处理函数的状态?

每个线程都有自己的信号屏蔽字,但是信号的处理是进程中所有线程共享的。

闹钟定时器是进程资源,并且所有的线程都共享相同的闹钟。所以进程中的多个线程不可能互不干扰的使用闹钟定时器。

一般多线程程序中,会利用 pthread_sigmask 来屏蔽信号,利用 sigwait 来等待信号。

API

int pthread_attr_getdetachstate(const pthread_attr_t *restrict attr,
    int *detachstate);
int pthread_attr_setdetachsetate(const pthread_attr_t *restrict attr,
    int detachstate);

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);//如果仅仅希望改变默认线程栈的大小,又不想自己处理线程栈的分配问题,则可以使用

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);         

int pthread_mutex_consistent(pthread_mutex_t *mutex);

int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t * restrict attr,
    int *restrict pshared);
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr,
    int pshared);

int pthread_condattr_getpshared(const pthread_condattr_t * restrict attr,
    int *restrict pshared);
int pthread_condattr_setpshared(pthread_condattr_t *attr,
    int pshared);

int pthread_condattr_getclock(const pthread_condattr_t * restrict attr,
    int *restrict clock_id);
int pthread_condattr_setclock(pthread_condattr_t *attr,
    int clock_id);

int ftrylockfile(FILE *fp);
void flockfile(FILE *fp);
void funlockfile(FILE *fp);

int pthread_key_create(pthread_key_t *keyp,void (*destructor)(void*));
int pthread_key_delete(pthread_key_t key);

int pthread_once(pthread_once_t *initflag,void (*initfn)(void));

void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key,const void*value);

void pthread_testcancel(void);
int pthread_setcancelstate(int state,int *oldstate);
int pthread_setcanceltype(int type,int *oldtype);

int pthread_sigmask(int how,const sigset_t *restrict set,sigset_t *restrict oset);

int sigwait(const sigset_t *restrict set,int *restrict signop);
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!