初识Linux多线程编程

 

本文主要参考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_Flag1变为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,其执行情况如下。

初识Linux多线程编程_第1张图片

以上,确实表明两个子线程对全局变量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则用于发出条件变量为真的信号。截取代码的三次运行表现如下:

初识Linux多线程编程_第2张图片

初识Linux多线程编程_第3张图片

以上,可以看出程序第一次运行,thread2执行前thread1修改了g_flag的值,然而第二次运行时,thread2执行前thread1并未修改g_flag的值。

此外,这里条件变量为真的判断及pthread_cond_signal信号的发出之所以与thread_mutex_lock互斥锁一起使用,并在互斥锁(互斥)的保护下进行,是因为“某个特性条件”通常是在多个线程之间共享的某个变量。互斥锁允许这个变量可以在不同的线程中设置和检测。

4)对于例程第五条需求,个人认为博客文章中并没有严格实现,我理解的需求应是thread1或是thread2仅有其一可修改g_flag值,然后主线程检测到信号cong为真即退出。文章的实现方式如下:

初识Linux多线程编程_第4张图片

通过加入else分支,使g_flag仅可被修改一次,

初识Linux多线程编程_第5张图片

运行结果也很有意思,

初识Linux多线程编程_第6张图片

从第一次运行情况来看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);
}


由于初次接触多线程编程,文中难免会有理解不到位的地方

 

 

你可能感兴趣的:(Linux多线程编程,C/C++基础,Linux,之路,linux,多线程,pthread_create)