boost :: thread не обновляет глобальную переменную - PullRequest
0 голосов
/ 07 февраля 2020

Я использую функцию-обертку во внешнем программном обеспечении для запуска нового потока, который обновляет глобальную переменную, но все же это кажется невидимым для основного потока. Я не могу вызвать join (), чтобы не блокировать основной поток и не взломать программное обеспечение. boost :: asyn c, boost :: thread и boost :: packaged_task ведут себя одинаково.

uint32 *Dval;

bool hosttask1()
{

        while(*Dval<10)
        {
            ++*Dval;
            PlugIn::gResultOut << " within thread global value: " << *Dval << std::endl;    
            Sleep(500);
        }


return false;
}



void SU_HostThread1(uint32 *value)
{

Dval = value; 
*Dval = 2;
PlugIn::gResultOut << " before thread: " << *value <<  " before thread global: " << *Dval << std::endl;

    auto myFuture = boost::async(boost::launch::async,&hosttask1);

    //boost::thread thread21 = boost::thread(&hosttask1);
    //boost::packaged_task<bool> pt(&hosttask1);
    //boost::thread thread21 = boost::thread(boost::move(pt)); 
}

Когда я вызываю функцию:

number a=0 
su_hostthread1(a)
sleep(2) //seconds
result(" function returned "+a+"  \n")

OUTPUT:

before thread value: 2 before thread global value: 2
 within thread global value: 3
 within thread global value: 4
 within thread global value: 5
 within thread global value: 6
 function returned 2  
 within thread global value: 7
 within thread global value: 8
 within thread global value: 9
 within thread global value: 10

Есть идеи? Заранее спасибо!

Ответы [ 3 ]

1 голос
/ 08 февраля 2020

Если вы делитесь данными между потоками, вы должны синхронизировать доступ к этим данным. Двумя возможными способами являются мьютекс, защищающий указанные данные, и операции atomi c. Простая причина в том, что существуют кэши и переупорядочение чтения / записи (как CPU, так и компилятором). Это сложная топика c, и это ничего не может быть объяснено в ответе здесь, но есть несколько хороших книг, а также куча кода, который делает это правильно.

0 голосов
/ 08 февраля 2020

Следующий код правильно воспроизводит то, что я собираюсь сделать. В основном, поток обновляет глобальную переменную, которую основной поток правильно наблюдает.

#include "stdafx.h"
#include <iostream>

#include <boost/thread.hpp>
#include <boost/chrono.hpp>

unsigned long *dataR;

bool hosttask1()
{
    bool done = false;
    std::cout << "In thread global value: " << *dataR << "\n"; //*value11 <<  *dataL << 
    unsigned long cc = 0;
    boost::mutex m;

        while (!done)
        {
            m.lock();
            *dataR = cc;
            m.unlock();
            cc++;
            std::cout <<  "In thread loop global value: "<< *dataR << "\n";
            if (cc==5) done = true;
        }


return done;
}

void SU_HostThread1(unsigned long *value)
{
    dataR = value;
    std::cout << "Before thread value: " << *value << " Before thread global value: " << *dataR << "\n"; //*value11 <<  *dataL << 
    auto myFuture = boost::async(boost::launch::async, &hosttask1);
    return;
}

int main()
{
    unsigned long value =1;
    unsigned long *value11;
    value11 = &value;

    SU_HostThread1(value11);

    boost::this_thread::sleep(boost::posix_time::seconds(1));
    std::cout << "done with end value: " << *value11 << "\n";

    return 0;
}

output:

Before thread value: 1 Before thread global value: 1
In thread global value: 1
In thread loop global value: 0
In thread loop global value: 1
In thread loop global value: 2
In thread loop global value: 3
In thread loop global value: 4
done with end value: 4

Тем не менее, когда я копирую это точно в SDK внешнего программного обеспечения, Основной поток не обновляет глобальное значение. Есть идеи, как это так? Спасибо

вывод во внешнем программном обеспечении:

before thread value: 1 before thread global value: 1
In thread global value: 1
In thread loop global value: 0
In thread loop global value: 1
In thread loop global value: 2
In thread loop global value: 3
In thread loop global value: 4
done with end value: 1 
0 голосов
/ 07 февраля 2020

Вероятно, это связано с тем, что компилятор обычно не думает о многопоточности при оптимизации вашего кода. Если вы видели, как код проверяет значение несколько раз, и он знает, что в однопоточном режиме это значение не может измениться, поэтому он просто пропустил проверку.

Если вы объявите переменную как volatile, то, вероятно, она сгенерирует менее эффективный код, который проверяет чаще.

Конечно, вы также должны понимать, что когда записывается значение, существуют обстоятельства, когда не все могут быть записаны в одном go, поэтому, если вам не повезло, чтобы прочитать его обратно, когда оно наполовину написано, то вы получите обратно мусорное значение. Решение этой проблемы заключается в том, чтобы объявить его как std :: atomi c (который автоматически считается энергозависимым для оптимизатора), а затем будет выдан еще более сложный код, чтобы гарантировать, что запись и чтение не могут пересекаться (или другой процессор примитивы могут использоваться для небольших объектов, таких как целые числа)

большинство переменных не разделяются между потоками, и когда они есть, программист должен определить их и оптимизировать баланс с потребностями синхронизации потока во время проектирования.

...