当前位置: 首页 > news >正文

TLPI 第30 章 练习:Threads: Thread Synchronization

笔记和练习博客总目录见:开始读TLPI。

30-1

修改清单 30-1(thread_incr.c)中的程序,使得线程的 start 函数中的每个循环都输出 glob 的当前值以及某个唯一标识线程的标识符。线程的唯一标识符可以作为参数传递给创建线程的 pthread_create() 调用。对于这个程序,这意味着需要将线程 start 函数的参数改为指向包含唯一标识符和循环上限值的结构体的指针。运行程序,将输出重定向到文件,然后检查文件,看看当内核调度程序在两个线程之间交替执行时,glob 会发生什么变化。


清单 30-1为threads/thread_incr.c。

代码如下:

#include<pthread.h>#include"tlpi_hdr.h"staticvolatileintglob=0;/* "volatile" prevents compiler optimizations of arithmetic operations on 'glob' */typedefstruct{inttid;intloops;}Thread_args;staticvoid*/* Loop arg->loops times incrementing 'glob' */threadFunc(void*arg){Thread_args*targ=(Thread_args*)arg;intloc,j;for(j=0;j<targ->loops;j++){loc=glob;loc++;glob=loc;printf("t%d:%d\n",targ->tid,glob);}returnNULL;}intmain(intargc,char*argv[]){pthread_tt1,t2;Thread_args targ1,targ2;ints;targ1.loops=targ2.loops=(argc>1)?getInt(argv[1],GN_GT_0,"num-loops"):10000000;targ1.tid=1;targ2.tid=2;s=pthread_create(&t1,NULL,threadFunc,&targ1);if(s!=0)errExitEN(s,"pthread_create");s=pthread_create(&t2,NULL,threadFunc,&targ2);if(s!=0)errExitEN(s,"pthread_create");s=pthread_join(t1,NULL);if(s!=0)errExitEN(s,"pthread_join");s=pthread_join(t2,NULL);if(s!=0)errExitEN(s,"pthread_join");printf("glob = %d\n",glob);exit(EXIT_SUCCESS);}

运行如下,输出到日志文件out:

$ ./ex30-11000000>out $tail-fout t1:1998633 t1:1998634 t1:1998635 t1:1998636 t1:1998637 t1:1998638 t1:1998639 t1:1998640 t1:1998641 glob=1998641

由于没到2000000,说明日志文件out中肯定有重复的值,即t1:xxxx和t2:xxxx。

找出重复值:

$sed's/^...//'out|sort|uniq-D>out.repeat $wc-lout.repeat2720out.repeat

查看重复值,说明当数字很大时才会出现问题:

$moreout.repeat10001801000180100577110057711006209100620910077181007718...

对应日志文件out中的位置:

1000916行:t2:1000180...## 一直是t2的输出1000935行:t2:10001991000936行:t1:1000180......1006508行:t1:10057711006509行:t2:10057711006510行:t2:1005773## 日志文件中无t2:1005772......1006947行:t1:10062091006948行:t2:10062091006949行:t2:1006211## 日志文件中无t2:1006210

30-2

实现一组线程安全的函数,用于更新和搜索非平衡二叉树。这个库应该包括以下形式的函数(用途显而易见):

initialize(tree);add(tree,char*key,void*value);delete(tree,char*key)Booleanlookup(char*key,void**value)

在上面的原型中,树是一个指向树根的结构(你需要为此目的定义一个合适的结构)。树的每个元素都保存一个键值对。你还需要为每个元素定义一个结构,包括一个互斥锁,用来保护该元素,以确保同一时间只有一个线程可以访问它。initialize()、add() 和 lookup() 函数实现起来比较简单。delete() 操作则需要花费更多的精力。

不需要维护平衡树大大简化了实现的锁定需求,但也有风险,某些输入模式可能会导致树的性能很差。维护平衡树则需要在 add() 和 delete() 操作中在子树之间移动节点,这就需要更复杂的锁定策略。


此题暂无时间,先略过了。

http://www.jsqmd.com/news/1380220/

相关文章:

  • 5分钟掌握Minemap:无需安装Minecraft的地图查看器实战指南
  • Ansible自动化部署Node Exporter:运维监控的标准化实践
  • 模糊控制算法完整详解(C# 原生实现,无第三方库)
  • 202页满分PPT | 某生物产业园区产业生态圈整体分析报告
  • Unity项目上传GitHub全攻略:从.gitignore配置到可复现仓库搭建
  • Vite工程化前端集成Qwen Image多模态生图模型实战指南
  • 2026 苏州服装出口美国新规!合规物流避免货物扣留退运 - 生活动态圈
  • 量子场论与元初混沌一气对称规则对照
  • 微服务网关登录校验与JWT实战配置
  • 驾校网站建设方案如何打造高转化招生平台?全方位解析驾校网站建设方案落地实施
  • 【2014-04-04】【转】OpenGL ES 混合的理解
  • HS2汉化补丁完整指南:15分钟快速实现游戏中文界面
  • 新手也能上手 AI论文网站推荐:2026最新测评与对比
  • Vibe Coding:重塑前端开发体验的现代范式与实践指南
  • 低脂鱼丸哪家品质好:【深鲜季】配方清爽 - 17728098551
  • 大型品牌如何审核TikTok代运营报价?账号矩阵、本地化与KOC费用完整拆解及采购重点
  • 深入理解计算机系统原理与性能优化实战
  • 【2014-05-19】某《魔鬼训练营》读书笔记:msfpayload的使用及免杀工具
  • Linux PipeWire深度解析之pw_properties_new_dict调用流程与实战(五十七)
  • 神州数码交换机配置实战:从VLAN划分到安全策略全解析
  • Linux 终端命令速查表 -- 07 文件与文件夹速查表
  • LangGraph核心三要素与智能体构建实战:从状态管理到复杂工作流编排
  • 《专利法》规定,专利申请必须提交至国家知识产权局(CNIPA),由其依法进行形式审查和实质审查
  • BilibiliDown终极指南:如何轻松下载B站视频与高质量音频
  • 实点科技5系列一体式I/O EI5R模块介绍
  • 上证3966点,三拨人的三种活法
  • 无人机IC认证怎么选:沃德检测一站式路径解析 - 生活动态圈
  • 【面试】【数字IC基础】跨时钟域处理一(CDC,Clock Domain Crossing)(一)
  • GetQzonehistory:5分钟快速备份你的QQ空间完整历史记录
  • 【2014-04-27】使用SQLMAP注入DVWA