• 线程基础--线程控制


    3.  线程控制

       1). 线程属性
         目标:能够设置 线程的 detached/join 状态。线程栈的大小和最低地址等属性。
         detached/join 状态的差别
         当线程处于 分离状态(detached)时,线程结束时。os马上回收资源。

    主线程不能够调用pthread_join获取线程退出时的返回值。

        当线程处于 未分离状态(join)时,线程结束时。主线程 调用pthread_join获取线程退出时的返回值, 随后释放该线程资源
            
         a)数据类型 pthread_attr_t
         b)初始化及释放属性结构 pthread_attr_init  pthread_attr_destroy 
            初始化时 会分配内存。所以一定要与 _..destroy 函数相相应
         c)获取或设置线程分离状态 pthread_attr_setdetachstate      pthread_attr_getdetachstate
           有2种可选的状态值:
           PTHREAD_CREATE_DETACHED   分离状态
           PTHREAD_CREATE_JOINABLE   正常状态,能够使用pthread_join来获取状态
         d)应该获取pthread_atr_destroy的返回值,由于使用pthread_attr_init初始化的时候可能分配有内存,假设释放内存失败的话,
           会造成内存泄漏
         e)控制线程栈的空间的大小
           需求:多个线程的栈空间累计超过了进程的可用虚拟地址空间
                 线程调用函数的自己主动变量非常多,或者递归非常深
           1)管理stackaddr线程属性。管理stacksize线程属性
           pthread_attr_getstack
           pthread_attr_setstack 
           2)获取或设置线程栈的大小
           pthread_attr_setstacksize  系统帮助分配内存,自己不用管
           pthread_attr_getstacksize
           3)线程栈的保护
           默认大小为宏PAGESIZE,但改动了栈属性后。这个值就会变成0
           pthread_attr_getguardsize
           pthread_attr_setguardsize
         f)线程属性-并发度
           pthread_attr_setconcurency
           pthread_attr_getconcurency
     
       2). 同步属性 (线程的同步对象 (例:相互排斥量、读写锁、条件变量)的属性)
          实现同步的3种方式中的对象的属性
         a)相互排斥量属性 pthread_mutexattr_t
           1)初始化及释放  pthread_mutexattr_init pthread_mutexattr_destroy
           2)进程共享属性
             获取与设置共享属性 pthread_mutexattr_getpshared   pthread_mutexattr_setpshared
             PTHREAD_PROCESS_PRIVAE 进程内的多个线程能够訪问同一个同步对象,默认属性
             PTHREAD_PROCESS_SHARED 多个进程能够共享同一块内存区域  内存共享技术。

    将相互排斥量用于进程间对同一内存区訪问的同步

              
           3)相互排斥量类型属性
             目标:设置 同一线程对已上锁的相互排斥量再次上锁 是否 死锁等属性。

             PTHREAD_MUTEX_NORMAL   标准的相互排斥量类型。不做错误检查或死锁检查
             PTHREAD_MUTEX_DEFAULT  依赖于操作系统提供到其它类型的映射
             PTHREAD_MUTEX_ERRORCHECK 提供错误检查
             PTHREAD_MUTEX_RECURSIVE (递归锁)同意多次加锁,可是须要解锁相应次数 tmd,这个类型叫做递归锁
             获取与设置相互排斥量类型属性
             pthread_mutexattr_gettype  pthread_mutexattr_settype
         应用场景
         PTHREAD_MUTEX_RECURSIVE (递归锁) 当将现有的单线程接口放到多线程环境中时。使用递归锁
         例:
         
         
          同一线程中 func1、 func2分别对 相互排斥量加锁, 若不是用 递归锁则会出现死锁。
        
     
         b)读写锁属性 pthread_rwlockattr_t
            能够设置是否支持进程共享属性 (默觉得 仅仅支持 线程共享属性 )

         c)条件变量属性pthread_condattr_t
            能够设置是否支持进程共享属性 (默觉得 仅仅支持 线程共享属性 )
     
    4. 线程重入
         可重入函数--指在信号处理函数中。正在执行的程序被信号处理程序中断后,返回时 不能正确执行的函数。
        原因:(a)使用了静态数据结构--全局的,会被其它线程/信号处理函数 等 使用
         (b)调用了 malloc / free ( malloc 为它所分配的存储区维护一个链接表,运行信号处理函数时,进程可能正在改动
              该表,导致被破环)
        (c)标准I/O函数--大部分使用了 全局结构变量

         1)线程安全:假设一个函数同一时刻能够被多个线程安全地调用
         2)系统是否支持线程安全函数  sysconf(_POSIX_THREAD_SAFE_FUNCTIONS)
         非线程安全的原因:返回的数据存放在静态的内存缓存区。多个线程调用该函数的时候 会覆盖前面正在使用的区域。

         将其进行可重入,为其分配自己的缓存器。避免被其它线程干扰,能够保证是线程安全的。
         重入后的函数,成为线程安全,并不意味着 它对信号处理程序是可重入的。

    (请举例,不太懂??)


         3)异步-信号安全:假设函数对异步信号处理程序的重入是安全的
         4)锁文件的3个函数
           flockfile  ftrylockfile   funlockfile
           该锁是递归锁
         5)确保函数在进程里面仅仅被调用一次
           pthread_once_t var = PTHREAD_ONCE_INIT;
           pthread_once(&var, function);
     
    5. 线程私有数据
         一种 让存储和查询 数据 与 某个线程相关的 机制。避免 与其它线程 同步訪问的问题
         1)须要的数据类型: pthread_key_t
         2)创建私有数据的步骤
            pthread_key_t key;     
           a)pthread_key_create(&key, 清理函数地址) 一般通过pthread_once确保函数仅仅被运行一次。变量仅仅被初始化一次
           b)char* addr = pthread_getspecific(&key)
           c)为addr分配内存 malloc
           d)pthread_setspecific(&key, addr);
           e)pthread_key_delete删除key
           f)线程退出。运行清理函数地址
     
    6.  线程取消
         设置pthread_cancle 函数相关的属性项
         1)线程能够被设置为是否可取消
           pthread_setcancelstate(int state, int* oldstate)
         2)pthread_cancel仅仅是一个申请,仅仅有线程到达了取消点才会取消.
         3)延迟取消pthread_testcancel, 适合于没有取消点的函数
         4)设置取消的类型pthread_setcanceltype
     
    7.  线程与IO
         pread,pwrite 原子io操作
        例:
        线程A 
        lseek( fd, 300, SEEK_SET);
        read( fd, buf1, 100);
        线程B
        lseek( fd, 700, SEEK_SET);
        read( fd, buf2, 100);
        当 A运行完lseek,B在A调用read之前调用lseek, 最后 两线程 读取同一条记录 (对同一文件操作,后一个 偏移量设置 覆盖了前一个设置)。
        解决方法:
        pread--将偏移量设定和数据读取成为一个原子操作
        线程A
        pread( fd, buf1, 100, 300);
        线程B
        pread( fd, buf2, 100, 700);

    8.  线程与信号
     
        每一个线程有自己的信号屏蔽字。可是他们共享 
        1)同样的信号处理函数 2)该信号与某函数的绑定,一个信号绑定到某个函数,这个被全部线程共享, 他们仅仅能看到一个
        多个线程公用进程的信号屏蔽机制。除了2种情况以外:
        硬件故障的信号与计时器超时的信号,仅仅递送给某个线程。其他的信号会发送给全部线程
        pthread_sigmask
        sigwait 等待信号发送.  一般操作须要先堵塞信号,sigwait调用会取消信号的堵塞状态,直到新信号到来
        pthread_kill
        sigwait(sigset_t*, int* signo)
        sigwait的參数2表示捕获到的信号值
     
    9.  线程与fork
        pthread_atfork,理论内容相当多,过滤掉
        当线程调用fork时。就会为子进程创建整个进程空间的副本。包含从父进程继承的相互排斥量、读写锁和条件变量等。
        因此,假设父进程包括多个线程。子进程在fork返回后。没有调用exec (原来的地址空间会被丢弃)的话。就须要清理锁状态。
        pthread_atfork( void (*prepare)(void), void (*parent)(void),void (*child)(void));
        能够设置3个锁清理函数。

     

        prepare fork 由父进程 在fork创建子进程前调用。任务:获取父进程定义的全部锁。
        parent fork: fork创建子进程后,但在fork返回之前,在父进程中 调用。
        child fork :fork创建子进程后。但在fork返回之前。在子进程中 调用。
     
    10.  同一进程的全部线程共享同一个计时器

    11.  同一进程的全部线程共享同样的文件描写叙述符
  • 相关阅读:
    剑指 Offer 56 II. 数组中数字出现的次数 II
    剑指 Offer 57 II. 和为s的连续正数序列
    剑指 Offer 63. 股票的最大利润
    剑指 Offer 55 II. 平衡二叉树
    剑指 Offer 59 II. 队列的最大值
    剑指 Offer 57. 和为s的两个数字
    剑指 Offer 64. 求1+2+…+n
    239. 滑动窗口最大值
    剑指 Offer 58 I. 翻转单词顺序
    剑指 Offer 60. n个骰子的点数
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/6905522.html
Copyright © 2020-2023  润新知