TLPI 第30 章 练习:Threads: Thread Synchronization
笔记和练习博客总目录见开始读TLPI。30-1修改清单 30-1thread_incr.c中的程序使得线程的 start 函数中的每个循环都输出 glob 的当前值以及某个唯一标识线程的标识符。线程的唯一标识符可以作为参数传递给创建线程的 pthread_create() 调用。对于这个程序这意味着需要将线程 start 函数的参数改为指向包含唯一标识符和循环上限值的结构体的指针。运行程序将输出重定向到文件然后检查文件看看当内核调度程序在两个线程之间交替执行时glob 会发生什么变化。清单 30-1为threads/thread_incr.c。代码如下#includepthread.h#includetlpi_hdr.hstaticvolatileintglob0;/* 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(j0;jtarg-loops;j){locglob;loc;globloc;printf(t%d:%d\n,targ-tid,glob);}returnNULL;}intmain(intargc,char*argv[]){pthread_tt1,t2;Thread_args targ1,targ2;ints;targ1.loopstarg2.loops(argc1)?getInt(argv[1],GN_GT_0,num-loops):10000000;targ1.tid1;targ2.tid2;spthread_create(t1,NULL,threadFunc,targ1);if(s!0)errExitEN(s,pthread_create);spthread_create(t2,NULL,threadFunc,targ2);if(s!0)errExitEN(s,pthread_create);spthread_join(t1,NULL);if(s!0)errExitEN(s,pthread_join);spthread_join(t2,NULL);if(s!0)errExitEN(s,pthread_join);printf(glob %d\n,glob);exit(EXIT_SUCCESS);}运行如下输出到日志文件out$ ./ex30-11000000out $tail-fout t1:1998633 t1:1998634 t1:1998635 t1:1998636 t1:1998637 t1:1998638 t1:1998639 t1:1998640 t1:1998641 glob1998641由于没到2000000说明日志文件out中肯定有重复的值即t1:xxxx和t2:xxxx。找出重复值$seds/^...//out|sort|uniq-Dout.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:100621030-2实现一组线程安全的函数用于更新和搜索非平衡二叉树。这个库应该包括以下形式的函数用途显而易见:initialize(tree);add(tree,char*key,void*value);delete(tree,char*key)Booleanlookup(char*key,void**value)在上面的原型中树是一个指向树根的结构你需要为此目的定义一个合适的结构。树的每个元素都保存一个键值对。你还需要为每个元素定义一个结构包括一个互斥锁用来保护该元素以确保同一时间只有一个线程可以访问它。initialize()、add() 和 lookup() 函数实现起来比较简单。delete() 操作则需要花费更多的精力。不需要维护平衡树大大简化了实现的锁定需求但也有风险某些输入模式可能会导致树的性能很差。维护平衡树则需要在 add() 和 delete() 操作中在子树之间移动节点这就需要更复杂的锁定策略。此题暂无时间先略过了。