Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] Wątki modyfikujące konkretną linię w konsoli.

Ostatnio zmodyfikowano 2017-11-29 23:23
Autor Wiadomość
kmlkamilek
Temat założony przez niniejszego użytkownika
[C++] Wątki modyfikujące konkretną linię w konsoli.
» 2017-11-28 20:24:43
Nie mam pojęcia jaki dać tytuł, więc wymyśliłem coś takiego na poczekaniu. Gryzie mnie pewna rzecz. Na potrzeby pytania z góry załóżmy, że chcę napisać pewien menedżer pobierania, który będzie wykorzystywał API współbieżności. Pobieram 4 pliki. Chcę w konsoli wyświetlać aktualny postęp, który dla każdego pliku, byłby aktualizowany przez przeznaczony do tego wątek.

Chcę mieć coś takiego:


1. Downloaded 3 of 400 KB
2. Downloaded 5 of 250 KB
3. Downloaded 4 of 100 KB
4. Downloaded 8 of 120 KB

By na końcu otrzymać coś takiego:


1. Downloaded 400 of 400 KB
2. Downloaded 250 of 250 KB
3. Downloaded 100 of 100 KB
4. Downloaded 120 of 120 KB

C/C++
#include <iostream>
#include <string>
#include <thread>
#include <vector>
#include <atomic>
#include <mutex>
#include <chrono>
#include <random>

std::atomic < unsigned > counter;
std::mutex print_lock;

void print( unsigned index, unsigned bytes_to_download )
{
    using namespace std::chrono_literals;
    int i = 0;
    while( i < bytes_to_download )
    {
        if( print_lock.try_lock() )
        {
            std::cout << "\r" << index << ". Downloaded " << i + 1 << " of " << bytes_to_download << "KB" << std::flush;
            print_lock.unlock();
           
            i++;
            counter++;
            std::this_thread::sleep_for( 20ms );
        }
    }
}

int main()
{
    std::mt19937_64 rnd { std::random_device { }() };
    std::uniform_int_distribution < unsigned > dist( 100u, 500u );
    std::vector < std::thread > threads;
   
    for( unsigned i = 0; i < 8; i++ )
         threads.emplace_back( & print, i + 1, dist( rnd ) );
   
    for( auto && thread: threads )
         thread.join();
   
    std::cout << "\nDownloaded " << counter << " bytes\n";
    return 0;
}

Próbowałem zrobić coś sam, ale ten program wyświetla wynik w jednej linii z wątku, ktory akurat w danym momencie zablokuje sobie cout'a. Z góry dziękuję.

PS: Jeśli ktoś ma zamiar pisać, bym zrobił to w jednym wątku, w pętli i po prostu czyścić konsole, to niech nie pisze.
P-167367
Kinexity
» 2017-11-28 20:41:16
Jeżeli piszesz pod Win, to w WinAPI są funkcje służące do modyfikacji zawartości konsoli.
P-167369
kmlkamilek
Temat założony przez niniejszego użytkownika
» 2017-11-28 20:44:44
Wiem o tym, ale zależy mi by było to zaimplementowane, przy użyciu standardowego API c++.
P-167370
jankowalski25
» 2017-11-28 21:08:56
Standardowa biblioteka C++ sama z siebie nie zapewnia możliwości cofnięcia się o jeden wiersz do góry, jeśli o to pytasz (bo nie ma takiego znaku specjalnego).
P-167372
Kinexity
» 2017-11-28 21:16:24
C++ nie ma "standardowego API", a standardową bibliotekę. Konsola zawsze podlega pod system, więc nawet jeżeli nie chcesz używać systemowego API, to musisz skorzystać z np. Qt lub czegoś podobnego.

EDIT: Nie wspominając o tym, że w konsoli można pisać tylko w jednym punkcie jednocześnie.
P-167373
kmlkamilek
Temat założony przez niniejszego użytkownika
» 2017-11-29 23:23:15
@Kinexity
Miałeś rację. Na windowsie bez winapi nie jest to do ugryzienia, bo jednak trzeba manipulować pozycją kursora. Na uniksowych, sekwencje ucieczki ansi. Na siłę w windzie też można użyć ansi, ale na systemach starszych od Win 10, wsparcie dla ansi w konsoli jest domyślnie wyłączone.
P-167403
« 1 »
  Strona 1 z 1