互斥锁与条件变量(基于控制输出面试题的思考)

     昨天笔试唯品会时,遇到一道编程题:
编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推。’
     当时看到这道题时,就想到了要使用互斥锁和条件变量。奈何,没有深入了解过,只能干瞪眼。回来之后,在网上查了查资料,也找到了相关题目,故整理这篇文章,算是学习笔记吧。
     代码直接借用别人的,就不亲自写了。代码原出处为:http://blog.chinaunix.net/uid-26868581-id-3359815.html

#include  
#include  
#include  
#include  
#include  
#define DEBUG 1 

int num = 0; 
pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t qready=PTHREAD_COND_INITIALIZER;

void* thread_func(void *arg)
{
    int param = (int) arg;
    int i;

    for(i = 0; i < 10; i++)
    {
        pthread_mutex_lock(&mylock);

        while(param != num)
            pthread_cond_wait(&qready, &mylock);

        printf("%c", param + 'A');
        num = (num + 1) % 3;

        pthread_mutex_unlock(&mylock);
        pthread_cond_broadcast(&qready);
    }

    return (void *)0;
}

int main()
{
    int i;
    pthread_t tid[3];
    void *tret;

    for(i = 0; i < 3; i++)
        pthread_create(&tid[i], NULL, thread_func, (void *) i);
    for(i = 0; i < 3; i++)
        pthread_join(tid[i], &tret);    
}

     程序思想比较简单,定义一个互斥锁和条件变量,开辟三个线程。在线程中,首先对互斥锁上锁,当数字与当前进程号相同时,执行打印,否则条件变量等待中(注,进入条件等待后,会对互斥锁解锁。当收到信号,激活时,重新对互斥锁上锁)。
     程序中主要涉及到的知识点如下:
1.互斥锁与条件变量的初始化
pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t qready=PTHREAD_COND_INITIALIZER;
2.条件变量的等待方式
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
     等待条件有两种方式:条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEOUT,结束等待,其中abstime以与time()系统调用相同意义的绝对时间形式出现,0表示格林尼治时间1970年1月1日0时0分0秒。
     无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()(或pthread_cond_timedwait(),下同)的竞争条件(Race Condition)。mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。
3.激发条件的两种方式
     激发条件有两种形式,pthread_cond_signal()激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个;而pthread_cond_broadcast()则激活所有等待线程。
4.线程结束thread_join
     pthread_join使一个线程等待另一个线程结束。代码中如果没有pthread_join主线程会很快结束从而使整个进程结束,从而使创建的线程没有机会开始执行就结束了。加入pthread_join后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行。

你可能感兴趣的:(linux,C/C++)