面试题分享-多线程顺序打印奇偶数

目录

1.题目详情

2.解题思路

2.1.分析题目

2.2.解析思路

3.代码实现

4.运行结果


1.题目详情

昨天刷抖音,遇到一个面试题,描述如下:

**请使用两个线程,分别顺序交替打印奇数和偶数,直到10为止。**例如有两个线程,分别为线程1和线程2,线程1首先打印数字1,然后线程2打印数字2,接着线程1再打印数字3,线程2再打印数字4,依次交替运行直到10为止。

2.解题思路

2.1.分析题目

乍一看题目很简单,但是其中涉及了多线程、锁、线程同步等知识点,如果简单的使用互斥锁或者其他的锁恐怕不会是最好的答案。

2.2.解析思路

现在无非要解决两个问题,第一个问题:线程1需要打印奇数而线程2需要打印偶数;第二个问题:线程1执行完之后需要跳转到线程2执行。这其中就涉及到了线程切换如何实现,关键需要解决第二个问题。

抛开第一个问题不谈,要解决线程切换的问题,我们先使用互斥锁实现,采用一个全局变量(标记位)控制两个线程的执行顺序。如果标记位等于某一个值则执行线程1,执行完将标记位置为另一个状态值,线程2获取到标记位发生改变,则执行线程2,依次类推。

提到这种解题思路,这不就是信号量操作吗,线程1先执行,然后释放信号,线程2阻塞等待信号,然后执行。

3.代码实现

互斥锁代码实现:

cpp 复制代码
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t lock;
#define TARGET 10
int turn = 1;  //1: 表示轮到打印奇数 2: 表示轮到打印偶数

//打印奇数
void* print_odd(void* arg) {
    int num = 1;
    while (num <= TARGET) {
        pthread_mutex_lock(&lock);
        while (turn != 1) {
            pthread_mutex_unlock(&lock);
            continue;
        }
        printf("thread id:%lu, num:%d\n", pthread_self(), num);
        turn = 2;
        pthread_mutex_unlock(&lock);
        num += 2;
    }
    return NULL;
}

//打印偶数
void* print_even(void* arg) {
    int num = 2;
    while (num <= TARGET) {
        pthread_mutex_lock(&lock);
        while (turn != 2) {
            pthread_mutex_unlock(&lock);
            continue;
        }
        printf("thread id:%lu, num:%d\n", pthread_self(), num);
        turn = 1;
        pthread_mutex_unlock(&lock);
        num += 2;
    }
    return NULL;
}

int main() {

    //初始化锁
    pthread_mutex_init(&lock, NULL);

    pthread_t odd_thread, even_thread;

    //创建线程
    pthread_create(&odd_thread, NULL, print_odd, NULL);
    pthread_create(&even_thread, NULL, print_even, NULL);

    //等待线程结束
    pthread_join(odd_thread, NULL);
    pthread_join(even_thread, NULL);

    //销毁锁
    pthread_mutex_destroy(&lock);

    return 0;
}

打印奇数线程首先运行,turn为标记位,如果标记位为1则打印奇数并修改标记位,如果标记位不是1则释放锁等待;打印偶数线程后运行,标记位初始状态为1,等待标记位,待标记位修改之后,打印偶数。

信号量代码实现:

cpp 复制代码
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <semaphore.h>

#define TARGET 10

/* 奇数信号量 */
sem_t sem_odd;
/* 偶数信号量 */
sem_t sem_even;

static void *print_odd() {
    int num = 1;
    while (num <= TARGET) {
        sem_wait(&sem_odd);
        printf("thread id:%lu, num:%d\n", pthread_self(), num);
        num += 2;
        sem_post(&sem_even);
    }
    return NULL;
}

static void *print_even() {
    int num = 2;
    while (num <= TARGET) {
        sem_wait(&sem_even);
        printf("thread id:%lu, num:%d\n", pthread_self(), num);
        sem_post(&sem_odd);
        num += 2;
    }
    return NULL;
}

int main()
{
    int ret = 0;
    //将奇数信号量初始值设为1 首先运行
    ret = sem_init(&sem_odd, 0, 1); 
    if (ret != 0) {
        printf("init sem_odd failed, ret:%d\n.", ret);
        return -1;
    }
    
    //将偶数信号量初始值设为0 其次运行
    ret = sem_init(&sem_even, 0, 0);
    if (ret != 0) {
        printf("init sem_even failed, ret:%d\n.", ret);
        return -1;
    }

    pthread_t thread1 = 0;
    pthread_t thread2 = 0;
    pthread_create(&thread1, NULL, print_odd, NULL);
    pthread_create(&thread2, NULL, print_even, NULL);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    return 0;
}

设置两个信号量,一个信号量用于控制打印奇数,一个信号量用于控制打印偶数;奇数信号量初始化为1,首先运行,偶数信号量初始化为0,其次运行;打印奇数线程运行完之后发送偶数信号量运行信号,偶数信号量运行完成之后发送奇数信号量运行信号,依次交替打印奇偶数。

4.运行结果

两个线程依次交替打印奇偶数:

相关推荐
minji...几秒前
算法题 逆波兰表达式/计算器
数据结构·c++·算法·1024程序员节
zhilin_tang1 小时前
Linux IPC 为什么要这么架构
linux·c语言·架构
小莞尔1 小时前
【51单片机】【protues仿真】基于51单片机自动售货机系统
c语言·单片机·嵌入式硬件·物联网·51单片机
编码追梦人1 小时前
基于 STM32 的智能语音唤醒与关键词识别系统设计 —— 从硬件集成到算法实现
stm32·算法·struts
循着风3 小时前
二叉树的多种遍历方式
数据结构·算法
.格子衫.8 小时前
022数据结构之树状数组——算法备赛
数据结构·算法·1024程序员节
黑科技Python8 小时前
生活中的“小智慧”——认识算法
学习·算法·生活
Yupureki8 小时前
从零开始的C++学习生活 16:C++11新特性全解析
c语言·数据结构·c++·学习·visual studio
ScilogyHunter9 小时前
C语言标准库完全指南
c语言·开发语言
sali-tec9 小时前
C# 基于halcon的视觉工作流-章52-生成标定板
开发语言·图像处理·人工智能·算法·计算机视觉