请在linux 利用c语言编程实现两个线程按照顺序依次输出”ABABABAB......“ (信雅达)

目录

题目

信号量实现

思路分析

代码

条件变量实现

思路分析

代码


题目

请在linux 利用c语言编程实现两个线程按照顺序依次输出”ABABABAB......" (信雅达)

例如a线程输出”A”之后b线程输出”B”,然后a线程输出“A”,再b线程输出”B”,之后往复循环。

信号量实现

思路分析

一、整体功能概述

创建一个子线程执行 funB 函数,同时在主线程中进行一系列操作,通过两个信号量 sem0 和 sem1 来协调两个执行路径的执行顺序,使得它们交替输出字符 A 和 B

 

二、主要函数和变量分析

 
  1. funB 函数:

    • 这是子线程执行的函数。
    • 在一个无限循环中,首先调用 sem_wait(&sem0) 等待信号量 sem0,这意味着子线程会在此处阻塞,直到信号量 sem0 的值大于 0。
    • 当信号量 sem0 可用时,输出字符 B,并使用 fflush(NULL) 刷新输出缓冲区,确保字符立即输出。
    • 然后调用 sleep(1) 暂停子线程执行 1 秒钟。
    • 最后调用 sem_post(&sem1),将信号量 sem1 的值加 1,以通知主线程可以继续执行。
  2. main 函数:

    • 首先定义了一个 pthread_t 类型的变量 tid,用于存储子线程的标识符。
    • 接着调用 pthread_create(&tid, NULL, funB, NULL) 创建一个子线程,并传入 funB 函数作为子线程的执行函数。如果创建子线程失败,会输出错误信息并返回 -1
    • 然后分别初始化两个信号量 sem0 和 sem1sem_init(&sem0, 0, 0) 将信号量 sem0 初始化为 0,表示初始状态下子线程会在等待这个信号量。sem_init(&sem1, 0, 1) 将信号量 sem1 初始化为 1,表示初始状态下主线程可以立即获取这个信号量并开始执行。
    • 在一个无限循环中,主线程首先调用 sem_wait(&sem1) 等待信号量 sem1,当信号量 sem1 可用时,输出字符 A,刷新输出缓冲区,然后调用 sem_post(&sem0),将信号量 sem0 的值加 1,通知子线程可以继续执行。
 

三、执行流程分析

 
  1. 程序开始执行,在 main 函数中创建子线程和初始化信号量。
  2. 由于初始状态下信号量 sem0 的值为 0,子线程会在 sem_wait(&sem0) 处阻塞等待。
  3. 主线程由于初始状态下信号量 sem1 的值为 1,可以立即通过 sem_wait(&sem1),然后输出字符 A,并将信号量 sem0 的值加 1。
  4. 子线程被唤醒,执行输出字符 B,暂停 1 秒,然后将信号量 sem1 的值加 1。
  5. 主线程再次被唤醒,重复上述过程,如此循环交替输出字符 A 和 B

四、应用场景和注意事项

 
  1. 应用场景:这种同步机制可以用于需要两个不同执行路径相互协作、交替执行任务的情况,例如在多线程环境下协调不同的操作顺序。
  2. 注意事项:
    • 确保在合适的时候销毁信号量,以避免资源泄漏。
    • 考虑在程序退出时正确地终止子线程和主线程,避免出现死锁或资源未释放的情况。
    • 注意多线程编程中的竞争条件和数据一致性问题,确保对共享资源的访问是正确同步的。

代码

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>
#include <unistd.h>

sem_t sem0, sem1;

void *funB(void *arg)
{
    while (1)
    {
        sem_wait(&sem0);
        printf("B");
        fflush(NULL);
        sleep(1);
        sem_post(&sem1);
        }
}
int main(int argc, char const *argv[])
{
    pthread_t tid;
    if (pthread_create(&tid, NULL, funB, NULL) != 0)
    {
        perror("pthread err");
        return -1;
    }
    if (sem_init(&sem0, 0, 0) != 0)
    {
        perror("init0 err");
        return -1;
    }
    if (sem_init(&sem1, 0, 1) != 0)
    {
        perror("init1 err");
        return -1;
    }

    while (1)
    {
        sem_wait(&sem1);
        printf("A");
        fflush(NULL);
        sem_post(&sem0);
    }
    return 0;
}

条件变量实现

思路分析

一、整体功能概述

通过互斥锁(pthread_mutex_t)和条件变量(pthread_cond_t)的组合,使得线程 funA 和线程 funB 能够按照特定的顺序交替执行输出操作,分别输出字符 A 和 B

二、主要函数和变量分析

  1. funA 函数:

    • 这个函数是线程 tid1 执行的函数。
    • 首先使用 sleep(2) 暂停执行 2 秒,模拟一些初始化操作或等待其他资源准备好。
    • 在一个无限循环中,每次循环先使用 sleep(1) 暂停 1 秒。
    • 然后获取互斥锁 lock,接着输出字符 A,并使用 fflush(NULL) 刷新输出缓冲区确保字符立即输出。
    • 调用 pthread_cond_signal(&cond) 发送信号,通知正在等待条件变量 cond 的线程(即 funB 所在的线程)。
    • 最后释放互斥锁 lock
    • 最后通过 pthread_exit(NULL) 退出线程。
  2. funB 函数:

    • 这个函数是线程 tid2 执行的函数。
    • 首先使用 sleep(1) 暂停执行 1 秒,可能是为了与线程 funA 的执行时间有所区分。
    • 在一个无限循环中,首先获取互斥锁 lock
    • 然后调用 pthread_cond_wait(&cond, &lock),这个函数会原子地释放互斥锁 lock,并等待条件变量 cond 被触发。当条件变量被触发时,函数会重新获取互斥锁并继续执行。
    • 接着输出字符 B,并刷新输出缓冲区。
    • 最后释放互斥锁 lock
    • 在函数结束处通过 putchar('\n') 输出一个换行符,然后通过 pthread_exit(NULL) 退出线程。
  3. main 函数:

    • 首先定义了两个 pthread_t 类型的变量 tid1 和 tid2,用于存储两个线程的标识符。
    • 接着初始化互斥锁 lock 和条件变量 cond,分别使用 pthread_mutex_init(&lock, NULL) 和 pthread_cond_init(&cond, NULL)
    • 使用 pthread_create(&tid1, NULL, funA, NULL) 创建线程 tid1,并传入 funA 函数作为线程执行的函数。如果创建失败,会输出错误信息并返回 -1
    • 同样使用 pthread_create(&tid2, NULL, funB, NULL) 创建线程 tid2,并传入 funB 函数作为线程执行的函数。如果创建失败,会输出错误信息并返回 -1
    • 然后使用 pthread_join(tid1, NULL) 和 pthread_join(tid2, NULL) 分别等待线程 tid1 和 tid2 结束,确保程序在所有线程都执行完毕后才退出。

三、执行流程分析

  1. 程序开始执行,在 main 函数中初始化互斥锁和条件变量,并创建两个线程。
  2. 线程 tid1(执行 funA 函数)先暂停 2 秒,然后进入无限循环。每次循环暂停 1 秒后,获取互斥锁,输出字符 A,发送条件变量信号,然后释放互斥锁。
  3. 线程 tid2(执行 funB 函数)先暂停 1 秒,然后进入无限循环。在循环中,获取互斥锁后,等待条件变量被触发。一旦条件变量被触发,输出字符 B,然后释放互斥锁。
  4. 由于线程 tid1 先执行并发送条件变量信号,线程 tid2 在等待条件变量后被唤醒并输出字符 B。然后两个线程交替执行,不断输出 A 和 B
  5. 最后,当程序需要退出时,在 main 函数中等待两个线程结束,然后清理资源并退出程序。

四、应用场景和注意事项

  1. 应用场景:这种同步机制适用于需要两个或多个线程按照特定顺序执行任务的情况,例如生产者 - 消费者问题、线程间的协作和同步等。
  2. 注意事项:
    • 确保在合适的时候销毁互斥锁和条件变量,以避免资源泄漏。
    • 注意互斥锁和条件变量的正确使用顺序,避免出现死锁或错误的同步行为。
    • 考虑在多线程环境下可能出现的竞争条件和数据一致性问题,确保对共享资源的访问是正确同步的。

代码

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t lock;
pthread_cond_t cond;

void *funA(void *arg)
{
    sleep(2);
    while (1)
    {
        sleep(1);
        pthread_mutex_lock(&lock);
        printf("A");
        fflush(NULL);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&lock);
    }

    pthread_exit(NULL);
}
void *funB(void *arg)
{
    sleep(1);
    while (1)
    {
        pthread_mutex_lock(&lock);
        pthread_cond_wait(&cond, &lock);
        printf("B ");
        fflush(NULL);
        pthread_mutex_unlock(&lock);
    }
    putchar('\n');
    pthread_exit(NULL);
}

int main(int argc, char const *argv[])
{
    pthread_t tid1, tid2;
    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&lock, NULL);

    if (pthread_create(&tid1, NULL, funA, NULL) < 0)
    {
        perror("tid1 err");
        return -1;
    }
    if (pthread_create(&tid2, NULL, funB, NULL) < 0)
    {
        perror("tid1 err");
        return -1;
    }

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    return 0;
}

 

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值