7天掌握pthread

纸上得来终觉浅,绝知此事要躬行。

对于入门/掌握/认知/学习某个东西/项技能,最好的方法是顶一个小目标,虽然我们这个目标与王首富的目标差距有点大,仍然需要付出持续的努力,然后完成它。所以有了这个7天掌握pthread的小目标,然后每天利用碎片时间去完成它。为何用碎片的时间呢?因为工作时间是属于公司的,只能利用碎片时间提升工作以外的技能。

最前

1,这不是一篇教程,是一篇日记,记录了每天学习的概要。
2,这篇文章不涉及pthread的高级内容,只为入门与初级掌握,因此不涵盖调度、属性、键、线程和信号,线程和fork,这些高级内容可参考APUE。
3,主要参考资料:详细简单

第1天

1,pthread_join()会堵塞,等待线程的结束。
2,waitpid(),option标识通常设置为0,堵塞等待子进程结束,设置不堵塞标识,WOHANG,会立刻返回。

第2天

1,pthread_t 在64Ubuntu下是64位整数,所以输出格式用ld或者lx。
2,把线程改为先创建,然后统一join,提示:使用array。
3,线程可以创建线程,他们是平等的,写一个迭代创建线程的demo。
4,共享内存图。
5,主线程cancel所有子线程,线程收到cancel后有两种看线程状态了,但是收到cancel后后面的代码就不会执行了。

pthread缺点:
6,虽然pthread是POSIX标准,各平台都实现了POSIX,但是实现细节不一样,如支持的线程数量,线程栈大小,因此pthread程序不一定具有良好的可移植性。

7,相爱相杀v1:
同一进程内,左膀右臂,恩爱情仇,分成两派,左膀负责制造线程,右臂负责杀死线程,造一个,杀一个。需要mutex保护一个共享变量。

第3天

1,线程捆绑:捆绑到某个CPU或核,POXIS不支持。但某些实现可能支持,函数是pthread_setaffinity_np, pthread_getaffinity_np,其中np指non portable,即不可移植。
2,pthread_exit()是线程自杀,可以向join传递退出status,缺陷是它不执行cleanup,不关闭线程内打开的文件。
3,特例:main函数调用pthread_exit()会阻塞,保持alive,为了是让他创建的线程继续执行,直到,所有子线程都结束,不论是不是它创建的,不论是否detached,相当于一次性join所有子线程。
4,特例测试:main创建一个线程child,child创建grandchild,然后child结束,看grandchild是否会结束。
5,pthread_函数返回的错误码,要直接打印,不要调用perror,因为perror打印的是全局的ERRNO,它随时万变,当perror输出的时候,它极有可能改变了,通常是这样。
6,相爱相杀v2:
他俩这样杀了很多年,感情更加纠缠,左膀加快了制造速度,右臂一时间反应不过来,一会杀的快,一会杀的慢。
rwlock保护一个共享队列。
7,设置线程属性的流程:定义属性变量,初始化,设置,释放属性变量。
8,在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。所以,如果知道一个线程永远不会被join,那么将属性设置为detach系统会释放一些资源。
9,POSIX没有限制线程栈大小,默认大小由实现决定,安全的可移植的程序,应当显式设置栈大小。
10,pthread_once (once_control, init_routine)一个神奇的函数,创建线程,并且这个线程在进程中只执行一次,用来做初始化操作。

第4天

1, 条件变量是线程同步的另外一种方式,互斥量是通过控制数据访问实现,条件变量是允许线程依赖数据实际的值。
2,如果没有条件变量,程序员需要不断检查条件(变量)是否改变,非常浪费资源。
3,条件标量总是和互斥量一起使用。
4,条件变量使用顺序:
pthread条件变量执行顺序
解释:
线程A:

  • 干活,直到到达需要条件变量的地方
  • 互斥量上锁
  • 调用pthread_cond_wait(),在这里等待线程B,它会先解锁互斥量,
  • 收到信号后,加锁信号量
  • 干活,与条件标量保护的那各变量
  • 解锁互斥量
  • 继续

线程B:

  • 干活
  • 互斥量上锁
  • 改变条件变量保护的变量
  • 互斥量解锁
  • pthread_cond_signal()通知线程A
  • 继续

pthread条件变量

5,条件变量信号多播pthread_cond_broadcast(),当多个线程等待条件变量时。

第5天

1,将相爱相杀v1,改成条件变量。
2,pthread_con_wait(),必须出现在pthread_cond_signal()之前,不然这个signal就浪费了,等待的线程阻塞在哪,程序就不正常执行。
3,调试工具:TotalView,未学习。
4,开发环境软件,涉及调试,内存查看检测,回溯,性能分析等。链接

第6天

1,ps命令可以显示线程信息,线程被称为轻量级进程(Light Weight Process),所以简称LWP,ps参数-L是显示线程,-f参数会显示多列信息,当LWP列与PID列值相同代表是主线程,最后跟进程号,查看某个进程的信息。ps -Lf PID
2,pstree命令,查看进程树结构。后面可以直接跟PID,或者User,查看某个进程的树,或者某个用户所有进程的树。-p参数表示显示进程号。-g显示组好,还有更多参数。pstree -p steve | grep process_name可以查看steve的进程和线程,根据进程名字过滤。pstree -p 55764可以查看进程55764的树结构。
3,pstack命令可以查看进程的跟踪栈, 参数为进程号。
4, top命令,-H参数会以县城为单位列出资源占用信息,-p参数可以指定要观察的进程号。所以top -Hp pid,很实用。
5,MPI,消息传递接口,主要用户分布式并行系统中,进程、县城数据传递,有一些第三方的MPI库,如OPenMP。MPI是通信协议的上层(高于运输层),所以可供多种语言实用。
6,键,线程的私有数据,线程保护自己私有数据的方式。
7,线程和IO,文件是线程共享的,在某个时刻,只有保证只有一个线程访问文件才能保证正确,所以需要原子操作的读写,使用pread和pwrite,它们不是pthread的一部分。
8,IO练习,使用多线程实现文件的拷贝,增加文件校验,确保拷贝无错误,与cp命令对比性能。额外练习,增加深度拷贝,可以拷贝整个目录。
9,core文件的产生与调试。ulimit -a显示所有资源限制,其中core文件打下为-c,所以ulimit -c就可以查看core文件,Ubuntu 16.04默认为0,ulimit -c 1024就可以设置core文件大小为1024字节,有人讲如果core文件大于设置的值会截断,但经本处测试,core文件并不产生,ulimit -c unlimited就会产生了,因为core文件41M。

总结

I hear, I know.
I see, I remember.
I do, I understand.