• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Tablica wątków C++ Visual Studio 2019

VPS Starter Arubacloud
0 głosów
454 wizyt
pytanie zadane 14 listopada 2020 w C i C++ przez Stefan Marzec Użytkownik (710 p.)

Witajcie. Przychodzę z kolejnym problemem, mimo że poprzedni nie został rozwiązany. Mianowicie robię czat internetowy w C++ z użyciem SFML. Najpierw klient wysyła serwerowi po UDP Nick, a ten odsyła wolny port do połączenia po TCP. Ten mechanizm mam już ogarnięty. Problem pojawia się gdy wydzielam osobny wątek dla dalszej komunikacji z tym klientem. Stworzyłem tablicę listeningThread[5], i przy każdym połączeniu z klientem wywołuję jej konstruktor z funkcją (łatwiej by było wywoływać jakąś metodę, ale czegoś takiego nie znalazłem), więc w pętli piszę listeningThread[i] = std::thread(listeningFunc(...)). Visual Studio Com 2019 wypluwa: "C2440 <function-style-cast>: nie można konwertować z "void" na "std::thread" " oraz "żadne wystąpienie konstruktora " E0289 std::thread::thread" nie jest zgodne z listą argumentów" dla linii 49. Po zmianie typu funkcji na int niby przyjmuje, ale wywala inne: " C2672 Invoke: nie znaleziono zgodnej przeciążonej funkcji l.43" i "C2893    Specjalizacja szablonu funkcji „unknown-type std::invoke(_Callable &&) noexcept(<expr>)” nie powiodła się  l.39"

Pomoże ktoś? 

#include <iostream>
#include <thread>
#include <mutex>
#include <SFML/Network.hpp>

unsigned short ports[5], clientPort, clientUdpPort;

std::thread listeningThread[5];

sf::TcpSocket listeningSocket[5];
sf::TcpSocket sendingSocket[5];

void listeningFunc(sf::IpAddress functionAddress) {
    
}



int main() {
    sf::UdpSocket choosingPortSocket;
    sf::Packet clientNamePacket;
    sf::IpAddress clientAddress;
    std::string clientName;

    
    for (int i = 0; i < 5; i++) {
        if (choosingPortSocket.bind(50000) != sf::Socket::Done) {
            std::cout << "ERROR with: Binding UDP Socket\n";
            return 0;  
        }
        ports[i] = 50001 + i * 2;

        if (choosingPortSocket.receive(clientNamePacket, clientAddress, clientUdpPort) != sf::Socket::Done) {
            std::cout << "ERROR with: Receiving client name with UDP\n";
            return 0;
        }
        
         clientNamePacket >> clientName;
         clientNamePacket.clear();
         clientNamePacket << ports[i];
         if (choosingPortSocket.send(clientNamePacket, clientAddress, clientUdpPort) != sf::Socket::Done) {
             std::cout << "ERROR with: Sending connect port to Client" << i << " with UDP\n";
             return 0;
         }
         std::cout << "Succesfully sended port to Client " << i << " Name: " << clientName << " on port: " << ports[i] << std::endl;

         listeningThread[i] = std::thread(listeningFunc(clientAddress));
    }
    listeningThread[0].join();
    

    

    return 0;
}

 

komentarz 14 listopada 2020 przez Oscar Nałogowiec (29,290 p.)
Po co ta zabawa z portami? Taki protokół nie będzie działa przez NAT.
komentarz 15 listopada 2020 przez Stefan Marzec Użytkownik (710 p.)
edycja 15 listopada 2020 przez Stefan Marzec
Właściwie dlaczego?

2 odpowiedzi

+1 głos
odpowiedź 14 listopada 2020 przez tangarr Mędrzec (154,780 p.)

Spójrz na konstruktor klasy thread w dokumentacji https://en.cppreference.com/w/cpp/thread/thread/thread.
Masz 3 konstruktory: domyślny, przenoszący, przyjmujący funkcję wraz z parametrami oraz usunięty konstruktor kopiujący (obiektu nie można kopiować).
Przekazując do konstruktora wywołanie listeningFunc(clientAddress) próbowałeś przekazać do konstruktora wynik funkcji czyli void.
Spójrzmy teraz na konstruktor który najbardziej cię interesuje

template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );

Konstruktor przyjmuje funkcję (może to być wskaźnik do funkcji, lambda lub funktor (obiekt, który może być wywołany jak funkcja), oraz listę argumentów dla tej funkcji.

Jeżeli twoja funkcja listeningFunc  wymaga podania argumentu typu sf::IpAddress to powinieneś go przekazać do konstruktora.

listeningThread[i] = std::thread(listeningFunc, clientAddress);

 

0 głosów
odpowiedź 14 listopada 2020 przez Stefan Marzec Użytkownik (710 p.)
No dobra, niedługo po dodaniu pytania udało mi się do tego samemu dojść, więc zostawię dla potomnych, choć również nie mam pewności, ale działa. Podczas wywoływania funkcji w konstruktorze chyba nie można podawać jej żadnych argumentów. Po usunięciu argumentów i nawiasów funkcji (czyli wpisałem samą jej nazwę) o tak: listeningThread[i] = std::thread(listeningFunc) zadziałało. Poprawcie mnie jeżeli coś źle rozumuję.

Podobne pytania

0 głosów
0 odpowiedzi 115 wizyt
0 głosów
2 odpowiedzi 536 wizyt
pytanie zadane 29 stycznia 2021 w C i C++ przez Maciek Pestka Nowicjusz (220 p.)
0 głosów
1 odpowiedź 546 wizyt

92,451 zapytań

141,261 odpowiedzi

319,073 komentarzy

61,853 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...