【问题标题】:Multithreaded program runs while loop extra times多线程程序在循环额外时间时运行
【发布时间】:2015-11-08 08:31:36
【问题描述】:

我正在做一个家庭作业,我必须用 C 语言编写一个多线程 linux 程序来解决操作系统类的生产者-消费者问题。在我的代码中,我有一个 while 循环,它位于由单个线程运行的函数内部。在该函数中,我有一个变量的增量,该变量受mutex 保护。

问题在于,while 循环运行的时间有时会超出我的预期。例如,当我希望循环执行16 次时,它有时会执行17 次。我无法弄清楚这个错误的原因,但它似乎与线程有关。我已经最小化了我的代码,问题仍然可以重现。

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>

int numItems = 16;
pthread_t threadID;
pthread_t threadID2;

pthread_mutex_t mutex;

pthread_attr_t attr;


void *produce(void *param);

int numItemsProduced = 0;

int main(int argc, char *argv[])
{

    pthread_attr_init(&attr);
    // Initialize mutex.
    if (pthread_mutex_init(&mutex, NULL) != 0)
    {
        printf("%s\n", "An error occured while initializing mutex!");
    }

    pthread_create(&threadID, &attr, produce, NULL);

    pthread_create(&threadID2, &attr, produce, NULL);

    pthread_join(threadID, NULL);
    pthread_join(threadID2, NULL);


    printf("Finished.\n");
}


void *produce(void *param)
{
    printf("In thread.\n");
    while (numItemsProduced < numItems)
    {
        pthread_mutex_lock(&mutex);
        printf("Current while loop is at int %d\n", numItemsProduced);

        numItemsProduced++;

        pthread_mutex_unlock(&mutex);
    }

    pthread_exit(0);
}

为什么while 循环有时会执行额外的时间?我相信我正确使用了mutex

【问题讨论】:

    标签: c multithreading while-loop pthreads mutex


    【解决方案1】:

    这个问题是线程进入while循环后等待互斥锁引起的。输入关键代码后需要再次检查条件:

    pthread_mutex_lock(&mutex);
    if (numItemsProduced < numItems){
        printf("Current while loop is at int %d\n", numItemsProduced);
        numItemsProduced++;
    }
    
    pthread_mutex_unlock(&mutex);
    

    【讨论】:

      【解决方案2】:

      你的问题在下面一行

      while (numItemsProduced < numItems)
      

      由于您尚未锁定互斥锁,因此此行中没有线程安全性。 您应该锁定互斥锁以检查条件和更新值。

      可以改写为:

      while (1)
      {
          pthread_mutex_lock(&mutex);
          if (numItemsProduced >= numItems)
          {
               pthread_mutex_unlock(&mutex);
               break;
          }
          printf("Current while loop is at int %d\n", numItemsProduced);
      
          numItemsProduced++;
          pthread_mutex_unlock(&mutex);
      }
      

      或者如果使用 c++:

      struct LockGuard
      {
           LockGuard(pthread_mutex_t* mutex) : _pmutex(mutex) 
           { 
               pthread_mutex_lock(_pmutex);
           };
      
           ~LockGuard() 
           { 
                pthread_mutex_unlock(_pmutex);
           }
         private:
           LockGuard(const LockGuard&); // or use c++0x ` = delete`
      
           pthread_mutex_t* _pmutex;
      };
      
      while (true)
      {
          LockGuard(&mutex);
          if (numItemsProduced >= numItems)
          {
               break;
          }
          printf("Current while loop is at int %d\n", numItemsProduced);
      
          numItemsProduced++;
      }
      

      【讨论】:

      • break; 语句会跳过pthread_mutex_unlock(&amp;mutex); 并导致死锁吗?
      • 会删除break; 语句并将if 块留空防止死锁吗?我不太了解 RAII,使用它感觉不舒服。
      • 如果你从如果线程永远不会退出函数中删除中断。如果你真的觉得使用 RAII 不舒服,你可以在 break 之前的 if 里面加上 onother unlock,但是你应该学习 RAII,这是一个非常重要的概念,它将确保你总是释放资源(并且在其他情况下很有用以及)。
      • 如果你要写c++对c问题的答案,你至少应该提到它。
      【解决方案3】:
      void *produce(void *param)
      {
          printf("In thread.\n");
          while (1)
          {
              pthread_mutex_lock(&mutex);
              if(numItemsProduced >= numItems){
                  pthread_mutex_unlock(&mutex);
                  break;
              }
              printf("Current while loop is at int %d\n", numItemsProduced);
      
              numItemsProduced++;
      
              pthread_mutex_unlock(&mutex);
          }
      
          pthread_exit(0);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-24
        • 2012-11-04
        • 2020-02-25
        • 2013-12-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-08
        相关资源
        最近更新 更多