使用std::thread的C++多线程应用程序在Windows上运行良好,但在Ubuntu上则不然

C++ multithreaded application using std::thread works fine on Windows but not Ubuntu

本文关键字:但在 Ubuntu 运行 Windows thread std C++ 多线程 应用程序 使用      更新时间:2023-10-16

我有一个稍微简单的多线程应用程序,它使用C++std::thread库为Ubuntu 14.04和Windows 8.1编写。代码几乎完全相同,只是我使用操作系统各自的库windows.h和unistd.h来使用Sleep/Sleep暂停执行一段时间。它们实际上都开始运行,Ubuntu版本确实运行了很短时间,但后来挂起了。我对sleep/sleep函数使用了正确的参数,因为我知道Windows睡眠需要几毫秒,而Unix睡眠需要几秒钟。

我已经运行了多次代码,在Ubuntu上它从来没有超过两分钟,而我在windows上运行了两次,每次20分钟,然后多次,每次大约5分钟,看看我是否幸运。这只是与线程库不兼容,还是睡眠没有达到我认为的效果,或者其他什么?无限循环之所以存在,是因为这是一个学校项目,预计运行时不会出现死锁或崩溃。

要点是,这是一个经过修改的4向停车,第一个到达的汽车不必减速停车。我们一次只需要让一辆车通过十字路口,需要3秒的时间,因此睡眠(3000),不必担心转弯。三个线程运行spawnCars函数,另外四个线程分别监视N、E、S和W四个方向中的一个。我希望这是可以理解的,为什么我不能发布整个代码,以免其他学生偶然发现。这两个函数是唯一的位置,除了顶部包含的依赖于操作系统的库之外,代码是不同的。谢谢

edit:由于我刚刚发布了该项目的所有代码,如果问题最终导致死锁,我可以请求您只这么说,而不发布深度解决方案吗?我是新来的,所以如果这违背了so的精神,那就开火吧,我会在不阅读细节的情况下努力弄清楚。

        /* function clearIntersection
        Makes a car go through the intersection.  The sleep comes before the removal from the queue
        because my understanding is that the wait condition simulates the go signal for drivers.
        It wouldn't make sense for the sensors to tell a car to go if the intersection isn't yet
        clear even if the lock here would prevent that.
        */
        void clearIntersection(int direction)
        {
            lock->lock();
            Sleep(3000);
            dequeue(direction);
            lock->unlock();
        }
        /* function atFront(int direction)
        Checks whether the car waiting at the intersection from a particular direction
        has permission to pass, meaning it is at the front of the list of ALL waiting cars.
        This is the waiting condition.
        */
        bool isAtFront(int direction)
        {
            lock->lock();
            bool isAtFront = cardinalDirections[direction].front() == list->front();
            lock->unlock();
            return isAtFront;
        }

        void waitInLine()
        {
            unique_lock<mutex> conditionLock(*lock);
            waitForTurn->wait(conditionLock);
            conditionLock.unlock();
        }
        //function broadcast(): Let all waiting threads know they can check whether or not their car can go.
        void broadcast()
        {
            waitForTurn->notify_all();
        }
    };
    /* function monitorDirection(intersectionQueue,int,int)
    Threads will run this function.  There are four threads that run this function
    in total, one for each of the cardinal directions.  The threads check to see
    if the car at the front of the intersectionQueue, which contains the arrival order
    of cars regardless of direction, is the car at the front of the queue for the
    direction the thread is assigned to monitor.  If not, it waits on a condition
    variable until it is the case. It then calls the function to clear the intersection.
    Broadcast is then used on the condition variable so all drivers will check if they
    are allowed to pass, which one will unless there are 0 waiting cars, waiting again if not the case.
    */
    void monitorDirection(intersectionQueue *intersection, int direction, int id)
    {
        while (true) //Do forever to see if crashes can occur.
        {
            //Do nothing if there are no cars coming from this direction.
            //Possibly add more condition_variables for each direction?
            if (!intersection->empty(direction))
            {
                while (!intersection->isAtFront(direction))
                    intersection->waitInLine();
                intersection->clearIntersection(direction);
                cout << "A car has gone " << numberToDirection(direction) << endl;
                //All cars at the intersection will check the signal to see if it's time to go so broadcast is used.
                intersection->broadcast();
            }
        }
    }

罪魁祸首很可能是while (!isAtFront(...))循环。如果在检查和对waitInLine()的后续调用之间安排了另一个线程,那么队列的状态可能会发生变化,导致所有使用者线程最终都在等待。在这一点上,没有线程来通知您的condition_variable,所以他们将永远等待。

相关文章: