引言

分享关于线程的一道测试题,因为网上基本都是Java的解决方法,决定自己写一篇来记录一下线程的学习。

问题描述

编写一个至少具有三个线程的程序(称之为线程 A、B 和 C),其中线程 A 输出字符’A’,线程 B 输出字符’B’,线程 C 输出字符’C’。使得最终输出结果为“ABCABCABC…”。

思路

拿到这题后,我的想法是把问题简化
原题让我们交替打印ABC,那么我们只要先考虑如何交替打印AB即可,然后在B之后衔接C,在C之后衔接A即可。

那么,如何使两个线程能够按照顺序去执行任务呢?
关于线程同步,首先我们想到的是互斥锁mutex。
但是mutex的缺点很明显,只有简单的拿锁和解锁两个状态,并且你无法保证谁先拿锁,也就是说你没法保证两个线程按照顺序去执行任务。
在Linux中,为了配合互斥锁mutex的使用,引入了条件变量cond。
它允许一个线程阻塞,直到另一个线程唤醒它。因此,我们可以想到用cond来实现顺序,解出题目。

具体的思路是:
设置三个不同的条件变量,分别代表前置线程是否结束任务时间(这样才能一环套一环才能保证线程按照顺序打印呀);配套这些条件变量的是三个互斥锁,分别代表哪个线程处于任务时间。
例如说,负责打印A的线程A的先等待标志线程C已经结束任务的条件变量唤醒,我们命名为c_over,来表示线程C已经结束任务。线程C结束任务后,轮到线程A工作了,此时线程A拿锁,同样的我们把这把锁命名为a_time,表示是线程A的工作时间,此时线程B和线程C都不会工作。最后,线程A打印出字符A后,释放这把a_time,表示线程A结束任务,同时通过a_over唤醒线程B。

注意点

一、
如果所有线程都像上述这么做,也就是所有线程都等待条件变量唤醒而阻塞着,没法工作。

解决方案
在主线程中唤醒线程A

二、
若在主线程中直接使用return 0退出,内核会回收掉整个进程的资源,结束其余线程的任务。

解决方案
在主线程中调用pthread_exit()或是在最后加上一行while (1);

代码

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <pthread.h>

pthread_mutex_t a_time, b_time, c_time; 
pthread_cond_t a_over = PTHREAD_COND_INITIALIZER;
pthread_cond_t b_over = PTHREAD_COND_INITIALIZER;
pthread_cond_t c_over = PTHREAD_COND_INITIALIZER;

void my_err(const char *str)
{
     perror(str);
     exit(1);
}

void *func_a(void *arg)
{
    while (1)
    {
        pthread_mutex_lock(&a_time);
        pthread_cond_wait(&c_over, &a_time);
        putchar('A');
        pthread_mutex_unlock(&a_time);
        pthread_cond_signal(&a_over);
    }
}

void *func_b(void *arg)
{
    while (1)
    {
        pthread_mutex_lock(&b_time);
        pthread_cond_wait(&a_over, &b_time);
        putchar('B');
        pthread_mutex_unlock(&b_time);
        pthread_cond_signal(&b_over);
    }
}

void *func_c(void *arg)
{
    while (1)
    {
        pthread_mutex_lock(&c_time);
        pthread_cond_wait(&b_over, &c_time);
        putchar('C');
        pthread_mutex_unlock(&c_time);
        pthread_cond_signal(&c_over);
    }
}

int main(int argc, char *argv[])
{
    pthread_t tid_a, tid_b, tid_c;
    pthread_mutex_init(&a_time, NULL);
    pthread_mutex_init(&b_time, NULL);
    pthread_mutex_init(&c_time, NULL);
    pthread_create(&tid_a, NULL, func_a, NULL);
    pthread_create(&tid_b, NULL, func_b, NULL);
    pthread_create(&tid_c, NULL, func_c, NULL);
    pthread_cond_signal(&c_over);
    pthread_exit( (void*)0 );   //while (1);
}
Logo

更多推荐