本文主要参考http://www.cnblogs.com/skynet/archive/2010/10/30/1865267.html
一个看起来简单而实际涉及很多细节的关于多线程编程的实例,文章主要以该实例展开讲解,例程如下
是否熟悉POSIX多线程编程技术?如熟悉,编写程序完成如下功能:
1)有一int型全局变量g_Flag初始值为0;
2)在主线称中起动线程1,打印“thisis thread1”,并将g_Flag设置为1
3)在主线称中启动线程2,打印“thisis thread2”,并将g_Flag设置为2
4)线程序2需要在线程1退出后才能退出
5)主线程在检测到g_Flag从1变为2,或者从2变为1的时候退出
主要介绍了:
a) 进程与线程;
b) 使用线程的理由;
c) 有关线程操作的函数;
d) 线程之间的互斥;
e) 线程之间的同步;
f) 试题最终代码
编程测试过程遇到的问题:
1)编译过程出现错误:undefined reference to `pthread_create',原因是pthread库不是标准linux库。编译选项应加上- lpthread,若要加入-o选项指定输出文件名,则必须将- lpthread选项置于最后,即gcc (-o target) X.C –lpthread
2)定义了全局变量g_flag = 0,主线程main函数中分别调用了两个子线程thread1,thread2,两个子线程函数中分别修改g_flag的值为1,2。然而,g_flag值改变前的输出总是0,而不是前一个线程修改后的值,也就是说全局变量在两个子线程执行后其值不变。为了验证猜想,在主线程函数main的两个子线程之间加入了语句g_flag= 3,其执行情况如下。
以上,确实表明两个子线程对全局变量g_flag值的修改在退出各自线程后失效了。Why?有这样一种可能,两个线程在打印第一条内容时,均没有其他线程对g_flag进行修改。(不过这就太巧了,两个线程应该严格按照交叉的顺序来执行,但我尝试了多次打印,竟没有一次按预期发生的,这还是巧合吗?很奇怪)
3)为了防止thread1与thread2同时对g_flag进行修改,使用了thread_mutex_lock线程锁对代码临界段进行锁定(这里是修改g_flag值的过程)以禁止其他线程访问同一资源;针对例程第四条需求,在线程thread2退出前使用了pthread_join函数阻塞其退出直至thread1先退出;针对例程第五条需求有“使用条件变量可以以原子方式阻塞线程,直到某个特定条件为真为止。条件变量始终与互斥锁一起使用。对条件的测试是在互斥锁(互斥)的保护下进行的”。因此,在主线程main函数中使用了pthread_cond_wait以阻塞主线程main函数退出直至条件变量cond为真,而pthread_cond_signal则用于发出条件变量为真的信号。截取代码的三次运行表现如下:
以上,可以看出程序第一次运行,thread2执行前thread1修改了g_flag的值,然而第二次运行时,thread2执行前thread1并未修改g_flag的值。
此外,这里条件变量为真的判断及pthread_cond_signal信号的发出之所以与thread_mutex_lock互斥锁一起使用,并在互斥锁(互斥)的保护下进行,是因为“某个特性条件”通常是在多个线程之间共享的某个变量。互斥锁允许这个变量可以在不同的线程中设置和检测。
4)对于例程第五条需求,个人认为博客文章中并没有严格实现,我理解的需求应是thread1或是thread2仅有其一可修改g_flag值,然后主线程检测到信号cong为真即退出。文章的实现方式如下:
通过加入else分支,使g_flag仅可被修改一次,
运行结果也很有意思,
从第一次运行情况来看thread2在第一次输出g_flag值时,其值为0;而接下来的if判断时,其值已经同步了thread2对g_flag的修改,g_flag = 1。这样,似乎确实这么巧,也验证了2)中的猜测。
下面是本文测试的最终代码:
#include
#include
#include
#include
#include
int g_flag = 0;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void *func1(void *);
void *func2(void *);
int main(int argc, char **argv)
{
printf("[main] enter\n");
pthread_t tid1, tid2;
int rc1 = 0, rc2 = 0;
rc1 = pthread_create( &tid1, NULL, func1, NULL );
if(0 != rc1)
{
printf("%s: %d\n", __func__, strerror(rc1));
}
//sleep(5); //单位s
//g_flag = 3;
rc2 = pthread_create( &tid2, NULL, func2, &tid1 );
if(0 != rc2)
{
printf("%s: %d\n", __func__, strerror(rc2));
}
pthread_cond_wait( &cond, &mutex ); //阻塞线程直至cond为真
printf("[main] leave\n");
exit(0);
}
void *func1(void *arg)
{
int val = 0;
printf("[func1] enter\n");
printf("this is thread1, g_flag = %d, t_id:%u\n", g_flag, (unsigned int)pthread_self());
pthread_mutex_lock( &mutex );
val = g_flag;
g_flag = 1;
if(2 == val)
{
printf("g_flag: 2 -> 1\n");
pthread_cond_signal( &cond );
}
pthread_mutex_unlock( &mutex );
printf("this is thread1, g_flag = %d, t_id:%u\n", g_flag, (unsigned int)pthread_self());
printf("[func1] leave\n");
pthread_exit(0);
}
void *func2(void *arg)
{
int val = 0;
pthread_t tid = *(pthread_t *)arg;
printf("[func2] enter\n");
printf("this is thread2, g_flag = %d, t_id:%u\n", g_flag, (unsigned int)pthread_self());
pthread_mutex_lock( &mutex );
val = g_flag;
g_flag = 2;
if(1 == val)
{
printf("g_flag: 1 -> 2\n");
pthread_cond_signal( &cond );
}
pthread_mutex_unlock( &mutex );
printf("this is thread2, g_flag = %d, t_id:%u\n", g_flag, (unsigned int)pthread_self());
pthread_join( tid, NULL );
printf("[func2] leave\n");
pthread_exit(0);
}
由于初次接触多线程编程,文中难免会有理解不到位的地方