【2016/3】多线程编程 线程同步技术 线程锁 用户校验

来源:互联网 发布:扒别人的网站源码 编辑:程序博客网 时间:2024/05/16 10:58

线程的一些概念:

   父线程结束 子线程立马同归于尽

— 子线程受到进程级别的打击 整个家族会瞬间爆炸
线程具有进程特性 也具有PID
— 线程有两重身份: 1.线程身份 2.子进程身份
— 线程就是与亲族之间共享资源的轻量级进程, 共享父进程的空间

子线程创建的新线程是它的兄弟: 他们共享空间,身份均等
— 但是会有一个本质上为兄弟线程的父线程用来管理别的线程

   线程的栈是私有的

线程的优势是快,轻量级, 它是高速进程

   线程是程序调度的基本单位, 进程是资源分配的基本单位(独立的资源空间)

多线程是主进程中衍生的共享进程资源的线程的集合

线程的函数是库函数,是在用户空间运行

ps auxH 来查看线程
pstree -ap也可以查看线程
— 每个线程都具有其私有的PID 用大括号括起来的
线程的tid只在一个进程空间有效,离开进程空间就无效了
— 仅仅是用来标记子线程的信息,给予操作线程的机会
— tid才是我们操作的对象

创建线程:

int pthread_create(pthread_t *tidp,const pthread_attr_t *attr, (void*)(*start_rtn)(void*),void *arg);
 tidp: 返回的tid值 attr:线程的状态 一般使用NULL来赋值 start_rtn: 线程执行的函数 对函数的返回值与参数有要求 arg: 函数传入的参数

注意:

   线程只能调用 pthread_exit(NULL) 函数来退出, 如果调用exit则瞬间爆炸   线程分离: pthread_detach(pthread_t thread);   将分离的属性与主线程切断联系

在子线程结束后自动回收资源(*唯一的区别!)
— 与之相对的是线程回收程序:pthread_join(pthread_t thread, void *);
不能回收已经分离的回收程序, 这个程序就是给子线程收尸用的

pthread_equal():用来确认是不是给自己发, 防止发错
pthread_cancel():取消线程,是等到合适的时机取消! (取消点)
— 系统函数就有取消点
pthread_testcancel(void) 人为制造取消点 要加入到函数的重复路径上!
— 分离的子线程也可以被取消

Tips: 迭代与递归的区别? **

 循环不一定能被递归替换 反而是可以: 递归调用会占用栈空间,次数太多时会出现错误

pthread_setcanceltype(): 设置如何响应取消
pthread_setcancelstate(): 设置是否能被取消
pthread_sigmask()/kill(): 用法跟原来一样

练习:

1.通过多线程来拷贝文件 实现多线程的CP确定参数列表中每个文件的大小先, 然后再开始设计创建线程,并分配任务把CP 的文件的信息保存再结构体中 然后再传入结构体进行线程的拷贝可以有上限和下限 然后通过合理规则决定线程数量2.线程池!       一次性创建很多线程,挂起等待命令的到来       每次命令运行的时候,寻找一个池中闲置的线程       运行传入函数的命令       运行完之后再回收   int pthread_pool_create(int num_of_pthread);   --- 线程要活着挂起!   --- 记得设定线程MAX数量   int pthread_pool_mission(void * (*fn)(void *arg), void *arg);   --- 分配任务函数: 分配给线程池中某一个闲的函数   --- 返回值是分配成功与否, no wait!   int pthread_pool_end(void);   --- 想象怎么join掉所有的子进程! lwp?   --- 用返回值告诉用户成功与否!

线程属性:

sysconf(): 获取线程最大数量 return -1: 出错/没有限制
— 线程有栈的大小的上限
设置取消状态是在线程开始运行之后设定的:
pthread_setcancelstate();
pthread_setcanceltypde();

初始化/销毁结构体: pthread_attr_init()/destroy();
栈,栈地址、大小,栈警戒区,分离属性(2个宏)
— 函数在书上或者 man -k pthread_attr

Tips: 并不建议使用线程属性, 系统分配的一定是很好的

2016-1-23:

线程同步技术:

   1.线程锁   2.自旋锁   3.读写锁   4.条件变量

类似全局变量, 减少切换内存片段的代价
— 查找进线程的区别(Teacher Blog) 总结条数

线程锁: pthread_mutex_t

   1.普通锁: 加锁一次解锁一次                 |先等先得   2.嵌套锁: 可以重复加锁,解锁够了才开锁      |自由竞争 (可互斥 可计数)   3.纠错锁: 重复加锁报错,只能由本线程解锁    |先等先得   4.自适应锁:加锁一次 解锁一次               |自由竞争

— 通过函数初始化与销毁锁:
静态初始化: mutex = 宏值
动态初始化:

    pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t * attr);

— attr结构体设置

        pthread_mutexattr_init(); //初始化     pthread_mutexattr_settype();  //设置属性 才能动态初始化

删除锁之前先锁(失败则挂起等待)后解锁 确保没有人正在使用这个锁

           pthread_mutex_lock();        //加锁 出错就挂起           pthread_mutex_trylock();     //加锁 出错就返回           pthread_mutex_timedlock();   //加锁 超时就返回           pthread_mutex_unlock() ;     //解锁

穿插加锁是很危险的, 容易造成死锁
在红帽7.0的内核下 pthread库的解锁加锁中改变了 :
挂起的时候发现被解锁会慢一拍,会被剥夺使用CPU的能力
而正在使用锁的人解锁后继续抢夺资源时会立刻抢到锁
为解决这个问题,让使用锁的人usleep(10)一下有利于公平竞争

自旋锁:pthread_spinlock_t

   短程占用高频占用式   时刻等待着锁的资源,不停地询问是否锁是空闲的   对锁等待时间短的时候才使用自旋锁   希望快速等待到资源才使用: 对CPU的占用较高!

自旋锁没有种类:但是有是否线程间共享锁的创建参数(PTHREAD_PORCESS_PRIVATE/SHARED)

       pthread_spin_lock/trylock/unlock()

读写锁:pthread_rwlock_t

   读多写少的场景   一读多读 一写都禁 (为了取得写的权限 则不能有人正在读 也不能有人继续获得写权限)   可以避免饥渴问题, 取决于互斥问题   为了保护读写操作

也有初始化的静态宏值 在/usr/include/pthread.h中有定义 (有读优先和写优先类型)

   pthread_rwlock_init/destory/rdlock/wrlock/unlock/tryrdlock/trywrlock..

条件变量:pthread_cond_t

用于不知道何时释放锁的时候,处于盲等状态,使等待成为被动触发的状态
等事件触发之后再进行, 本质是一个全局变量
运用了事件编程的思想

与线程锁配合使用
一旦条件满足就唤醒因等待满足特定条件而睡眠的线程

优势是 等条件的线程们全部在挂起等待 不会消耗内存

类似于线程池的信号系统

       pthread_cond_signal();      //唤醒一个线程       pthread_cond_broadcast();   //唤醒所有线程 但是只有一个人拿到锁       //使用流程:           1.pthread_mutex_lock           2.pthread_cond_wait //内部会先解锁 然后等条件再加锁                               //保证每一个时间等待条件的人只有一个                               //串行挂起 先解锁后的所有人进入此行循环           3.pthread_mutex_unlock

用户校验

1.setuid 设置用户id 再之后的代码以该id身份执行
2.getspnam 传入用户名 返回的是一个带有用户身份的指针(含有密文密码)
getpwuid 得到uid (更好用)
3.crypt 对比明文与密文

1.模块化 可以拆装 宏内核
2.一个整体内核一块崩溃全体崩溃 微内核 –linux
— 查看两者区别

0 0
原创粉丝点击