Что может сделать две или более функций асинхронными в одном потоке (кроме как их вставки и компиляции с помощью O3)? - PullRequest
0 голосов
/ 20 сентября 2019

В этом тестовом примере:

#include<numeric>
#include<iostream>

inline void f1(char * buf) {
    (*buf) += 5;
}
inline void f2(char * buf) {
    (*buf) += 7;
}

int main()
{
    char ptr1,ptr2;
    std::cin>>ptr1;
    std::cin>>ptr2;
    f1(&ptr1);
    f2(&ptr2);

    return ptr1+ptr2;
}

, который скомпилирован в следующие коды сборки с использованием -O3 и -march = cannonlake (in godbolt)

main:
        sub     rsp, 24
        lea     rsi, [rsp+14]
        mov     edi, OFFSET FLAT:_ZSt3cin
        call    std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char> >(std::basic_istream<char, std::char_traits<char> >&, char&)
        lea     rsi, [rsp+15]
        mov     edi, OFFSET FLAT:_ZSt3cin
        call    std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char> >(std::basic_istream<char, std::char_traits<char> >&, char&)
        movzx   eax, BYTE PTR [rsp+14]    // f1 function entrance
        movzx   ecx, BYTE PTR [rsp+15]    // f2 entrance interleaved
        add     eax, 5                    // f1 compute
        lea     edx, [rcx+7]              // f2 compute using another instruction (ilp)
        movsx   eax, al                   
        movsx   edx, dl
        add     eax, edx
        add     rsp, 24
        ret
_GLOBAL__sub_I_main:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:_ZStL8__ioinit
        call    std::ios_base::Init::Init() [complete object constructor]
        mov     edx, OFFSET FLAT:__dso_handle
        mov     esi, OFFSET FLAT:_ZStL8__ioinit
        mov     edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
        add     rsp, 8
        jmp     __cxa_atexit

Это похоже на встраивание функцийпозволяет им преобразовываться в чередующуюся версию f1 + f2 и работать асинхронно на суперскалярном процессоре.Есть ли более прямой, формальный способ добиться этого?

Если я добавлю std :: async с отложенной политикой, он все равно будет чередовать инструкции функций с простыми вызовами f1 и f2, но на этот раз get() метод будущегоделает "вызов", и вызов там не перемежается из-за инструкции "jump" после этого.

Попробовал std :: async следующим образом:

f1(&ptr1);
f2(&ptr2);
std::async(std::launch::deferred,f1,&ptr1).get();
std::async(std::launch::deferred,f2,&ptr2).get();

Может быть, не только get ()но также конструкторы и деструкторы «будущего» также вызывают эти вызовы и переходы.

Как я могу запустить группу функций (или даже лямбда-выражения?) или одну функцию с различными параметрами (как будто обрабатывает массив) не прибегая к «встроенному» iness-функциям (поскольку компилятор не гарантирует этого)?Возможен ли мелкозернистый параллелизм в одном и том же потоке?

Asynchronizator(0,100,[]()
{ 
    runCode(parameter++); 
});

, если это возможно с лямбдами, было бы даже лучше, но у них тоже есть конструкторы и деструкторы, являющиеся функторами.

...