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

目录

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.运行结果

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

相关推荐
AI科技星4 小时前
从ZUFT光速螺旋运动求导推出自然常数e
服务器·人工智能·线性代数·算法·矩阵
老鼠只爱大米4 小时前
LeetCode经典算法面试题 #78:子集(回溯法、迭代法、动态规划等多种实现方案详细解析)
算法·leetcode·动态规划·回溯·位运算·子集
执着2595 小时前
力扣hot100 - 199、二叉树的右视图
数据结构·算法·leetcode
I_LPL5 小时前
day21 代码随想录算法训练营 二叉树专题8
算法·二叉树·递归
可编程芯片开发5 小时前
基于PSO粒子群优化PI控制器的无刷直流电机最优控制系统simulink建模与仿真
人工智能·算法·simulink·pso·pi控制器·pso-pi
cpp_25015 小时前
P8448 [LSOT-1] 暴龙的土豆
数据结构·c++·算法·题解·洛谷
lcj25115 小时前
深入理解指针(4):qsort 函数 & 通过冒泡排序实现
c语言·数据结构·算法
fie88895 小时前
基于MATLAB的转子动力学建模与仿真实现(含碰摩、不平衡激励)
开发语言·算法·matlab
唐梓航-求职中5 小时前
编程大师-技术-算法-leetcode-1472. 设计浏览器历史记录
算法·leetcode
_OP_CHEN5 小时前
【算法基础篇】(五十八)线性代数之高斯消元法从原理到实战:手撕模板 + 洛谷真题全解
线性代数·算法·蓝桥杯·c/c++·线性方程组·acm/icpc·高斯消元法