/*
* POSIX 下线程控制的实验程序残缺版
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <pthread.h>
#define MAX_THREAD 3 /* 线程的个数 */
unsigned long long main_counter, counter[MAX_THREAD]; /* unsigned long
long是比long还长的整数 */
void* thread_worker(void*);
int main(int argc, char* argv[])
{
int i, rtn, ch,a[];
pthread_t pthread_id[MAX_THREAD] = {0}; /* 存放每个线程的id */
for (i=0; i<MAX_THREAD; i++)
{
/* 在这里填写代码,用pthread_create建一个普通的线程,* 线程id存入pthread_id[i],
}
* 线程执行的函数是thread_worker,并i作为参数传递给线程 */
/* 用户按一次回车执行下面的循环体一次。按q退出 */
do
{
unsigned long long sum = 0;
/* 求所有线程的counter的和 */
for (i=0; i<MAX_THREAD; i++)
{
sum += counter[i];
printf("%llu ", counter[i]);
}
printf("%llu/%llu", main_counter, sum);
}
while ((ch = getchar()) != 'q');
return 0;
}
void* thread_worker(void* p)
{
int thread_num;
/* 在这里填写代码,把main中的i的值传递给thread_num */
for(;;) /* 无限循环 */
{
counter[thread_num]++; /* 本线程的counter加一 */
}
main_counter++; /* 主counter 加一 */
}
按照注释里的要求把代码补充完整,正确编译程序后,先预计一下这个程序的运行结果。具体的结果会是什么样?运行程序。开另一个终端窗口,运行“ps aux”命令,看看thread 的运行情况,注意查看thread 的CPU 占用率,并记录下这个结果。
--------------------------------------------------------------------------------------------------------------------------
当把这样的程序给学生时,很多人觉得无所适从。首先,以前从来没有接触过线程编程,而课程本身并不讲具体的线程编程,因此,关于Linux下的编程,要求学生自学。等大家自学一段时间后再来阅读这个程序,感觉这个程序难度不大,于是下手填写代价。动手之后首先遇到的问题是,给线程传递参数问题,在一次次传递出错后只好求助别人,当别人告诉你答案后,你欣喜地赶紧把代码填充上去,调试也很快通过,但是,藏在身后的多线程并发的问题又没有考虑到,于是试着一次次的加锁,当几次加锁后终于得到你想要的结果,又发现线程的并发度又降低了,如此等等。
当我一个个检查学生完成情况时,想偷懒和抄袭的同学乖乖地缴枪投降,因为 我不看正确的运行结果,那只有一种情况,而我的问题是:
1) 你在编写和调试过程中遇到哪些问题,采取了哪些方法去解决?
2)当给pthread_create()传递第四个参数时,这个参数如何表示,&i和 (void *)i传递的结果有什么样的差异
3)线程之间的同步问题如何解决,加锁的粒度是否合适?
等等...
如果有学生津津乐道给我讲他遇到了多少问题,怎么思考,又是如何解决,我就会鼓励他继续“犯错误”,试试另外一种错误会产生怎样的结果。因此说,所谓的举一反三并不是朝着一个正确的结果奔去,而是在有意或者无意制造的错误中找到乐趣并加深思考。