rn_xtcxyczjh-7 并发[线程3 嵌套锁与装饰模式]
来源:互联网 发布:淘宝客计划管理设置 编辑:程序博客网 时间:2024/06/14 03:04
2015.10.30
读xtcxyczjh(系统程序员成长计划)—- 学习程序设计方法。
个人笔记对应代码保存地址:y15m10d30
作者实现的是递归锁。
1. 需求简述
实现一个嵌套锁,要求如下:
- 嵌套锁仍然兼容Locker接口。
- 嵌套锁的实现不依赖于特定平台。
2. 准备
读《xtcxyczjh》P.46-P.48:
- 嵌套加锁造成的死锁:在同一线程中,连续加锁(程序会被阻塞在第二次线程加锁处)。
- 装饰模式:不改变对象的本质(接口)的前提下,给对象(锁)添加附加的功能(对一把锁进行装饰,不改变它的接口,但给它加上嵌套的功能)。
3. 代码
(1) 分析
- 嵌套锁的实现算法(P.46 —- 可能会导致线程中无必要加锁的代码加锁,如父函数加锁后调用前面有一大段代码都不用加锁的子函数)。
- 与平台相关的功能模块要用回调函数来抽象,如获取当前线程ID的函数、创建线程嵌入锁的函数等。
- 描述嵌入锁(装饰锁)的数据结构(保存线程的ID、计数、线程锁接口、获取线程ID函数指针等元素)。
(2) 实现
[1]装饰锁接口
因为不能改变线程锁的接口,故而需要另定义一个数据结构类型来描述“嵌入锁”以及“获取线程ID回调函数“等功能。利用C语言结构体实现变长数组的机制,将新定义的数据结构加到线程锁接口的对象中,这样就能够实现装饰模式。
描述装饰锁的数据结构。
/* locker.h *//* 定义不依赖于平台的线程锁接口 */#ifndef LOCKER_H#define LOCKER_H//……//锁接口struct _Locker { LockerLockFuncT lock; LockerUnlockFuncT unlock; char dcrt[0];};//装饰锁接口typedef int (*pGetThreadSelfIDFuncT)(void);typedef struct _DcrtLockT { int owner; //拥有锁的线程ID int count; //加锁计数器 pGetThreadSelfIDFuncT tid_self; //指向获取线程ID函数的函数指针}DcrtLockT;#endif
[2] 嵌入锁函数
创建嵌入锁函数。在cpthread.c中,将create_thread_locker函数修改为以下内容:
/* cpthread.c *//* 调用POSIX thread库中的函数定义线程线程相关函数 *///……//用户自定实现线程锁初始化函数Locker *create_thread_nest_locker(void){ //在这里添加您初始化线程嵌入锁的代码 Locker *locker = NULL; locker = (Locker *)malloc(sizeof(Locker) + sizeof(DcrtLockT)); if (NULL != locker) { DcrtLockT *pdcrt = NULL; pdcrt = (DcrtLockT *)locker->dcrt; locker->lock = lock_nest_thread; locker->unlock = unlock_nest_thread; pdcrt->owner = 0; pdcrt->count = 0; pdcrt->tid_self = get_thread_id; } //初始化此平台下的线程锁 lock_nest_init(); return locker;}
locker = (Locker *)malloc(sizeof(Locker) + sizeof(DcrtLockT));语句用DcrtLockT装饰了锁对象locker。装饰模式最有用的地方在于,它给单个对象增加功能,但不是影响调用者,即使加了多级装饰,调用者也不用关心。
根据创建线程锁函数的更改,修改其它地方的代码:
/* cpthread.h *//* 定义线程相关,或声明定义在cpthread.c中的调用POSIX thread库的函数 */#ifndef CPTHREAD_H#define CPTHREAD_H//……Locker *create_thread_nest_locker(void);//……#endif/* cpthread.c *//* 调用POSIX thread库中的函数定义线程线程相关函数 *///……//用户自定义实现获取线程ID函数static int get_thread_id(void){ //在这里添加获取当前线程ID的代码 return pthread_self();}//……
lock_nest_thread和unlock_nest_thread分别为线程加锁和解锁函数。
加锁函数。
/* cpthread.c *//* 调用POSIX thread库中的函数定义线程线程相关函数 *///……//用户自定义初始化线程锁函数static RetT lock_nest_thread(Locker *locker){ //在这里定义你的线程加锁代码 int ret = 0; DcrtLockT *pdcrt_locker = (DcrtLockT *)locker->dcrt; if (pdcrt_locker->owner == pdcrt_locker->tid_self()) { pdcrt_locker->count++; }else { ret = sem_init(&mutex, 0, 1); pdcrt_locker->count = 1; pdcrt_locker->owner = pdcrt_locker->tid_self(); } return ret == 0 ? RET_OK : RET_FAIL;}//……
如果当前线程已经加锁,只是增加加锁计数,否则就加锁。
解锁函数。
/* cpthread.c *//* 调用POSIX thread库中的函数定义线程线程相关函数 *///……//用户自定义实现的线程加锁函数static RetT unlock_nest_thread(Locker *locker){ //在这里定义你的线程加锁代码 int ret = 0; DcrtLockT *pdcrt_locker = (DcrtLockT *)locker->dcrt; return_val_if_p_invalid(pdcrt_locker->owner == pdcrt_locker->tid_self(), RET_FAIL); pdcrt_locker->count--; if (pdcrt_locker->count == 0) { pdcrt_locker->owner = 0; ret = sem_wait(&mutex); } return ret == 0 ? RET_OK : RET_FAIL;}//……
只有当前线程加的锁才能解锁,先减少加锁计数,计数为0时才真正解锁,否则直接返回。
修改原调用create_thread_locker函数的代码:
/* main.c *//* 包含C程序入口 */#include <stdio.h>#include "cpthread.h"#include <assert.h>#include "autotest.h"int main(void){ DlistManageT *pdl = NULL; unsigned int dlen = 10; single_thread_test(&pdl, dlen, NULL); free_dlist(pdl); pdl = NULL; multi_thread_test(&pdl, dlen, create_thread_nest_locker); free_dlist(pdl); return 0;}
因为本次代码都是通过装饰模式来完成的,关于线程锁接口以及双向链表程序都没有被改动过。所以在用户角度下修改代码后,可直接在与Makefile以及程序所在同目录下使用make命令。然后执行./all程序得到以下执行结果:
姑且算它运行正常。
读《xtcxyczjh》-Part-VII pnote over.
[2015.10.30-18:15]
- rn_xtcxyczjh-7 并发[线程3 嵌套锁与装饰模式]
- rn_xtcxyczjh-8 并发[线程4 读写锁接口]
- rn_xtcxyczjh-5 并发[线程1 线程执行模式-汇编指令层]
- rn_xtcxyczjh-9 并发[线程5 原子操作(volatile, inline, typeof, ({ep1;ep2;}), 内嵌汇编) 无锁数据结构]
- rn_xtcxyczjh-6 并发[线程2 头文件重复包含 函数返回值的统一 结构体中的变长数组 线程锁接口]
- Java与设计模式(3)--装饰模式
- I/O多路复用模式与线程并发模式
- IO流3与装饰模式见解
- cppunit与装饰模式
- 【java与模式】装饰模式
- Java多线程与并发应用-(3)-传统线程通信技术及生产者消费者模式
- 高效并发-线程安全与锁优化
- JVM-并发-线程安全与锁优化
- C++线程与并发
- C# 线程与并发
- java并发与线程
- 线程与并发基础知识
- java基础 IO/线程/GUI,装饰模式
- 【博客大赛】巧用FPGA中资源
- VS2010快捷键大全及设置
- java程序获取项目的路径
- Android仿微信/支付宝的方块密码输入框
- 我的单链表
- rn_xtcxyczjh-7 并发[线程3 嵌套锁与装饰模式]
- C++ CDialogEx 类的调用流程
- yii1.1随记
- Unity3D项目程序加密2——对dll进行混淆
- YTKNetwork 使用基础教程
- 浏览器工作原理
- hdu 2212 DFS
- c++函数模板的使用
- hexdump