ccb_ 2024-07-21 19:08 采纳率: 50%
浏览 2

多线程并发,C++,linux

我想通过互斥量,实现3个线程轮流输出字母,但是我运行的结果是一直输出小写字母a。想要实现的效果是abc重复出现.请问以下代码,哪里有问题?


#include <cstdio>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t mymutex[3];

int netx(int n)
{
    if (n + 1 == 3)
        return 0;
    else
        return n + 1;
        
}

void* print(void* p)
{
    
    int n = (long)p;
    int ch = 'a' + n;
   
    while(true)
    {
        //上锁
        pthread_mutex_lock(mymutex + n);

        write(1,&ch,1);

        //解锁
        pthread_mutex_unlock(mymutex + netx(n));
    }

    pthread_exit(NULL);

}

int main()
{


    pthread_t tid[3];
    int ret(0);
    
    for(int i = 0; i < 3; ++i)
    {
        //初始化锁
        pthread_mutex_init(mymutex + i, NULL);
        
        //上锁
        pthread_mutex_lock(mymutex + i);
        
        
        //创建线程
       ret = pthread_create(tid + i,NULL,print,(void*)i);

       if(ret)
       {
            fprintf(stderr, "create false");
            return 0;
       }

    }

    //解开一个锁
    pthread_mutex_unlock(mymutex);

    alarm(5);

    //给三个线程收尸
    for(int i = 0; i < 3; ++i)
    {
        pthread_mutex_destroy(mymutex + i);
        pthread_join(tid[i],NULL);
    }

    return 0;
}
  • 写回答

4条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-07-21 19:09
    关注

    引自免费微信小程序:皆我百晓生

    这是一个使用POSIX线程(pthread)和互斥锁(mutex)的C++多线程并发程序示例。你的代码中有一些问题和潜在的改进点。让我们一步步地解决它们。

    问题和解决方案:

    1. 线程函数中死循环问题:你的print函数是一个死循环,这意味着线程会一直运行下去,除非被某种方式中断。这可能导致你的程序永远不会结束。通常,你需要一种方法来让线程在完成任务后退出。在这个例子中,你可以使用pthread_exit()来结束线程。但更好的做法是在循环中使用一个标志变量来检查是否应该退出。
    2. 互斥锁的使用问题:你在解锁时使用了netx(n)函数的结果作为互斥锁的索引,这可能不是你想要的。因为该函数可能会导致解锁的互斥锁不是线程加锁的同一个互斥锁。你应该确保解锁的是线程自己加锁的互斥锁。
    3. 主线程退出问题:在主函数中,你设置了一个闹钟(使用alarm(5)),但没有处理SIGALRM信号。因此,当闹钟到期时,程序会默认终止,而不是按预期执行其他操作。你可能需要处理这个信号或者删除这个部分。

    基于上述问题,让我们对代码进行一些修改:

    修改后的代码:

    #include <cstdio>
    #include <cstdlib>
    #include <pthread.h>
    #include <unistd.h>
    #include <signal.h> // 为了处理SIGALRM信号
    
    pthread_mutex_t mymutex[3];
    bool should_exit = false; // 用于控制线程退出的标志变量
    
    void signal_handler(int signum) { // 处理SIGALRM信号的函数
        if (signum == SIGALRM) {
            should_exit = true; // 设置标志变量以退出线程
        }
    }
    
    void* print(void* p) {
        int n = (long)p;
        int ch = 'a' + n;
        while (!should_exit) { // 使用标志变量控制循环
            pthread_mutex_lock(mymutex + n); // 加锁
            write(STDOUT_FILENO, &ch, 1); // 使用STDOUT_FILENO代替数字1来写入标准输出,避免平台依赖性问题
            pthread_mutex_unlock(mymutex + n); // 解锁对应的互斥锁,而不是netx(n)的结果
            usleep(1000); // 添加延时以模拟工作负载(可选)
        }
        return NULL; // 正常退出线程
    }
    
    int main() {
        pthread_t tid[3];
        int ret = 0;
        signal(SIGALRM, signal_handler); // 注册信号处理器来处理SIGALRM信号
        for (int i = 0; i < 3; ++i) {
            pthread_mutex_init(mymutex + i, NULL); // 初始化互斥锁
            pthread_mutex_lock(mymutex + i); // 在创建线程之前锁定互斥锁(可选)以避免竞争条件在初始化阶段发生。但这通常不是必要的。注意这里不需要再解锁了。直接创建线程即可。        ret = pthread_create(&tid[i], NULL, print, (void*)i); // 创建线程而不立即解锁互斥锁以避免竞态条件(可选)如果删除这一行中的解锁操作,那么在创建线程之前不必加锁了。        if (ret) {            fprintf(stderr, "create false");            return 1;        }    }    alarm(5); // 设置闹钟以在5秒后触发SIGALRM信号    for (int i = 0; i < 3; ++i) {        pthread_mutex_destroy(mymutex + i); // 在主线程退出之前销毁互斥锁是必要的,否则会造成资源泄漏        pthread_join(tid[i], NULL); // 主线程等待子线程结束    }    return 0;}``` 在这个修改后的代码中,我添加了一个标志变量来控制线程的循环,并注册了一个信号处理函数来处理SIGALRM信号。这样,当闹钟到期时,主线程可以设置标志变量来通知所有工作线程退出。另外,我也使用了`usleep()`函数来模拟每个线程的工作负载(这取决于你的实际需求)。注意:在使用多线程编程时,还需要考虑数据共享和同步的问题以及潜在的竞态条件等问题,这取决于你的实际需求和环境设置来适当修改和优化代码。希望这可以帮助你解决问题!如果你有其他关于代码的问题或需要进一步的解释,请告诉我!
    
    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 7月21日

悬赏问题

  • ¥15 如何在vue.config.js中读取到public文件夹下window.APP_CONFIG.API_BASE_URL的值
  • ¥50 浦育平台scratch图形化编程
  • ¥20 求这个的原理图 只要原理图
  • ¥15 vue2项目中,如何配置环境,可以在打完包之后修改请求的服务器地址
  • ¥20 微信的店铺小程序如何修改背景图
  • ¥15 UE5.1局部变量对蓝图不可见
  • ¥15 一共有五道问题关于整数幂的运算还有房间号码 还有网络密码的解答?(语言-python)
  • ¥20 sentry如何捕获上传Android ndk 崩溃
  • ¥15 在做logistic回归模型限制性立方条图时候,不能出完整图的困难
  • ¥15 G0系列单片机HAL库中景园gc9307液晶驱动芯片无法使用硬件SPI+DMA驱动,如何解决?