您的位置:首页 > 编程语言

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

2016-03-19 23:27 357 查看

线程的一些概念:

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


— 子线程受到进程级别的打击 整个家族会瞬间爆炸

线程具有进程特性 也具有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

— 查看两者区别
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: