用互斥锁来管理交通
为了保护某段代码的安全,你需要创建互斥锁:
pthread_mutex_t a_lock = PTHREAD_MUTEX_INITIALIZER;
互斥锁必须对所有可能发生冲突的线程可见,也就是说它是一个全局变量。
PTHREAD_MUTEX_INITIALIZER
实际上是一个宏,当编译器看到它,就会插入创建互斥锁的代码。
- 红灯停。
你需要把第一盏红绿灯放在这段代码的开头,pthread_mutex_lock()
只允许一个线程通过,其他线程运行到这行代码时必须等待。
- 绿灯行。
当线程到达代码的尾部就会调用pthread_mutex_unlock()
把红绿灯调回绿灯,其他线程就能进入这段代码了:
既然你知道了怎么在代码中创建锁,也就能精确控制线程的行为了。
把long值传给线程函数
线程函数可以接收一个
void
指针作为参数,并返回一个void
指针值。通常你希望把某个整型值传给线程,并让它返回某个整型值,一种方法是用long
,因为它的大小和void
指针相同,可以把它保存在void
指针变量中。
练习
找到上锁的位置实非易事,而锁的位置会改变代码的运行方式。下面有两个不同版本的
drink_lots()
函数,它们以不同方式为代码上了锁。
两段代码都用互斥锁来保护
beers
变量的安全,并在退出前显示了beers
值。由于它们在不同的位置使用了锁,因此在屏幕上输出了不同结果。你能弄清哪段代码对应哪个版本吗?
练习解答
找到上锁的位置实非易事,而锁的位置会改变代码的运行方式。下面有两个不同版本的
drink_lots()
函数,它们以不同方式为代码上了锁。两段代码都用互斥锁来保护
beers
变量的安全,并在退出前显示了beers
值。由于它们在不同的位置使用了锁,因此在屏幕上输出了不同结果。请弄清哪段代码对应哪个版本。
恭喜!你已经(快要)看完这本书了。打开一瓶啤酒,庆祝一下吧!
是时候决定你将成为哪种类型的C程序员了。写纯C代码的Linux黑客?还是为Arduino那种小装置写嵌入式C的匠人?或是转而成为一名使用C++的游戏开发人员?或使用Objective-C的Mac及iOS程序员?
无论你的选择是什么,你都已经成为了C社区的一份子。在这里,你们使用同一种语言,并深深热爱着它。这种语言创建的软件比其他任何语言都要多;它是整个互联网和几乎所有操作系统的基础;几乎所有其他语言都是用它写的;几乎所有电子设备的处理器都可以用它来编程,大到飞机卫星,小到手表手机。
欢迎你!一年级C黑客!
这里没有蠢问题
**问:为了支持多线程,我的计算机必须有多个处理器吗?
答:不必。绝大多数计算机都使用多核处理器。也就是说CPU中有一些小型处理器,它们可以一次做几件事情。即便代码运行在一台单核/单处理器的计算机上,也还是能运行多线程程序。
问:怎么运行?
答:操作系统会在多个线程之间快速地切换,看起来就好像在同时做多件事。
问:线程能让程序变得更快吗?
答:也不一定,尽管线程可以帮助你利用机器上更多的处理器和核,但你还是需要控制代码中锁的数量,如果用了太多锁,代码可能会像单线程程序一样慢。
问:怎样设计高效的多线程程序?
答:减少线程需要访问的共享数据的数量。如果线程无需访问很多共享数据,那么多个线程等一个线程的情况就很少出现,速度会大大提高。
问:线程要比进程快?
答:通常是这样,因为创建进程要比创建线程花更多时间。
问:听说互斥锁会引发“死锁”,那是什么玩意儿?
答:假设你有两个线程,它们都想得到互斥锁A和B。倘若第一个线程得到了A,第二个线程得到了B,这两个线程就会陷入死锁。因为第一个线程无法得到B,第二个线程无法得到A,它俩都停滞不前。