使用线程的意外行为

Unexpected behavior using threads

本文关键字:意外 线程      更新时间:2023-10-16

我有一个函数,我想通过多线程优化。而不是用pBodiesBody对象的整个向量调用函数RenderBodies,就像我这样做的:

RenderBodies(pBodies);

我想调用它4次,每次使用pBodies向量的不同四分之一,并并行运行它们。

所以我像这样分割向量:

std::vector<Body*> Bodies1, Bodies2, Bodies3, Bodies4;
for (unsigned int i = 0; i < pBodies.size(); i += 4)
{
    Bodies1.push_back(pBodies[i]);
    Bodies2.push_back(pBodies[i + 1]);
    Bodies3.push_back(pBodies[i + 2]);
    Bodies4.push_back(pBodies[i + 3]);
}

然后使用带有新向量的线程,

std::thread t1(RenderBodies, pTarget, Bodies1, pZoom);
std::thread t2(RenderBodies, pTarget, Bodies2, pZoom);
std::thread t3(RenderBodies, pTarget, Bodies3, pZoom);
std::thread t4(RenderBodies, pTarget, Bodies4, pZoom);
t1.join();
t2.join();
t3.join();
t4.join();

但是结果是没有渲染。

问题是,RenderBodies函数没有任何问题,因为如果我使用这个:

RenderBodies(pTarget, Bodies1, pZoom);
RenderBodies(pTarget, Bodies2, pZoom);
RenderBodies(pTarget, Bodies3, pZoom);
RenderBodies(pTarget, Bodies4, pZoom);

它工作!但是它没有使用我的cpu的所有4核,所以它没有用。

为什么线程不能像预期的那样工作?

My Code inside RenderBodies():

sf::RectangleShape Temp;
    mtx.lock();
    for (unsigned int i = 0; i < param.pBodies.size(); i++)
    {
        if (param.pZoom > 1)
            Temp.setSize(sf::Vector2f(param.pBodies.at(i)->mass * param.pZoom, param.pBodies.at(i)->mass * param.pZoom));
        else
            Temp.setSize(sf::Vector2f(param.pBodies.at(i)->mass, param.pBodies.at(i)->mass));
        float AccelCoefficient = static_cast<float> (sqrt(param.pBodies.at(i)->AccelX * param.pBodies.at(i)->AccelX + param.pBodies.at(i)->AccelY * param.pBodies.at(i)->AccelY) * (20000 * _GRAV_CONST));
        if (AccelCoefficient > 1)
            AccelCoefficient = 1;
        float Red, Green, Blue;
        Blue = 1 - (AccelCoefficient);
        if (AccelCoefficient < 0.2)
            Red = (AccelCoefficient)* 5;
        else
            Red = 1;
        if (AccelCoefficient < 0.5)
            Green = (AccelCoefficient)* 2;
        else
            Green = 1;
        Temp.setFillColor(sf::Color(static_cast<sf::Uint8> (Red * 255), static_cast<sf::Uint8> (Green * 255), static_cast<sf::Uint8> (Blue * 255), 128));
        Temp.setPosition(static_cast<float>(param.pBodies.at(i)->posX), (static_cast<float>(param.pBodies.at(i)->posY)));
        param.pTarget->draw(Temp);
    }
    mtx.unlock()

如果不知道RenderBodies()函数在做什么,就不可能给出精确的答案。

然而,我的猜测是它与参数pTarget有关,该参数将相同的值传递给所有线程,并且(从名称)是一个指针。如果是这样,这意味着你有四个线程与一个对象交互——所以线程有必要同步对该对象的访问(例如使用互斥锁或临界区)。

如果线程除了渲染pTarget之外没有做太多的事情,同步访问它将否定多线程的大部分好处(因为,实际上,这会导致所有线程相互等待,并且所有的渲染都是顺序的)。

然而,事情就是这样。多线程并不是免费的午餐。获得性能的方法是尽量减少线程之间的同步(即使它们彼此等待)。如果你不这样做,你会得到竞争条件,所以操作可能无法正确完成——这就是你所描述的。

这就是为什么用户界面设计的一个指导方针通常是只有一个线程负责渲染窗口/屏幕。