12.8 多线程
至此,我们总是让程序的主执行线程仅仅创建一个线程。但我们并不想让读者认为你只能多创建一个线程。
实 验 多线程
在本章最后的例子thread8.c中,我们将演示如何在同一个程序中创建多个线程,然后又如何以不同于其启动的顺序将它们合并到一起。
运行这个程序时,将看到如下所示的输出结果:
如你所见,我们创建了许多线程并让它们以随意的顺序结束执行。这个程序有一个小漏洞,如果将sleep调用从启动线程的循环中删除,它就会变得很明显。我们通过它提醒读者,在编写使用线程的程序时需要多么小心。你发现错误在哪里了吗?我们将在下面的“实验解析”中解释它。
实验解析
这一次,我们创建了一个线程ID的数组,如下所示:
然后通过循环创建多个线程,如下所示:
创建出的线程等待一段随机的时间后退出运行,如下所示:
在主(原先)线程中,我们等待合并这些子线程,但并不是以创建它们的顺序来合并,如下所示:
如果删除sleep调用后再运行这个程序,就可能会看到一些奇怪的现象,比如一些线程以相同的参数被启动,你可能会看到类似下面的输出:
你能发现为什么会出现这样的问题吗?启动线程时,线程函数的参数是一个局部变量,这个变量在循环中被更新,引起问题的代码行是:
如果主线程运行得足够快,就有可能改变某些线程的参数(即lots_of_threads)。当对共享变量和多个执行路径没有做到足够重视时,程序就有可能出现这样的错误行为。我们已经警告过,编写线程程序时需要在设计上特别小心。要改正这个问题,我们可以直接传递这个参数的值,如下所示:
当然还要修改thread_function函数,如下所示:
这些修改都在程序thread8a.c中以阴影部分显示出来了,如下所示: