2

C++ でコーディングを始めたばかりで、マルチスレッド サーバーを構築しようとしていますが、エラーが発生しました。まず、ここに私が得たコードがあります:

while(true){
        printf("waiting for a connection\n");
        csock = (int*)malloc(sizeof(int));

        if((*csock = accept( hsock, (sockaddr*)&sadr, &addr_size))!= -1)
        {
            printf("---------------------\nReceived connection from   %s\n",inet_ntoa(sadr.sin_addr));
            //std::thread th(&Network::SocketHandler, NULL);

            std::thread th(Network::SocketHandler, (void*)csock);
            th.detach();
        }
        else
        {
            fprintf(stderr, "Error accepting %d\n", errno);
        }
    }

    }


    void Network::SocketHandler(void* lp)
    {
        int *csock = (int*)lp;

       char buffer[1024];
       int buffer_len = 1024;
       int bytecount;

       memset(buffer, 0, buffer_len);
       if((bytecount = recv(*csock, buffer, buffer_len, 0))== -1){
          fprintf(stderr, "Error receiving data %d\n", errno);

       }
       printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
       strcat(buffer, " SERVER ECHO");

       if((bytecount = send(*csock, buffer, strlen(buffer), 0))== -1){
          fprintf(stderr, "Error sending data %d\n", errno);

       }

       printf("Sent bytes %d\n", bytecount);

    }

この行でコンパイルするとエラーが発生します:

std::thread th(Network::SocketHandler, (void*)csock);

言って: std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (Network:: )(int ); _Args = {void*}] '' から 'void (Network:: &&)(int )' への引数 1 の既知の変換はありません</p>

どうすればこれを修正できますか? または、マルチスレッドサーバーを作成するより良い方法はありますか?他の投稿の例はありますか?

4

1 に答える 1

7

本当に欲しいのは であることが明らかなのに、なぜ のvoid *代わりにを渡すのですか?int *int *

関数のシグネチャを次のように変更するだけです。

void Network::SocketHandler(int* csock)

呼び出しを行うコードでキャストを削除します。

std::thread th(Network::SocketHandler, csock);

今でもエラーが発生しますが、それは別の理由によるものです。Network::SocketHandlerメンバー関数です。thisポインターが必要です。object.SocketHandler(csock)通常、このような関数はorのような構文で呼び出しますobjptr->SocketHandler(csock)。そのように呼び出すと、::std::thread呼び出されるオブジェクトが与えられません。thisポインターはありません。

すべきことは、関数のシグネチャを次のように変更することです。

static void Network::SocketHandler(int* csock)

そして、あなたのコードは問題なく動作します。関数がメンバー変数を使用していないように見えるため、thisポインターは必要ありません。

別のメモとして、もともと pthread 用に書かれたものを適応させようとしているようです。C++11 スレッド ライブラリに対してこれを行う場合は、かなり異なる方法で行います。

プログラム全体を見ることができないので、再設計する余裕はありません。しかし、私が見ることができるものから、私はこれらの微調整を行います:

while(true){
        printf("waiting for a connection\n");
        int csock = -1;

        if((csock = accept( hsock, (sockaddr*)&sadr, &addr_size))!= -1)
        {
            printf("---------------------\nReceived connection from   %s\n",inet_ntoa(sadr.sin_addr));
            //std::thread th(&Network::SocketHandler, NULL);

            std::thread th(Network::SocketHandler, csock);
            th.detach();
        }
        else
        {
            fprintf(stderr, "Error accepting %d\n", errno);
        }
    }

    }


    void Network::SocketHandler(int csock)
    {
       char buffer[1024];
       int buffer_len = 1024;
       int bytecount;

       memset(buffer, 0, buffer_len);
       if((bytecount = recv(csock, buffer, buffer_len, 0))== -1){
          fprintf(stderr, "Error receiving data %d\n", errno);

       }
       printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
       strcat(buffer, " SERVER ECHO");

       if((bytecount = send(csock, buffer, strlen(buffer), 0))== -1){
          fprintf(stderr, "Error sending data %d\n", errno);

       }

       printf("Sent bytes %d\n", bytecount);

    }

変更はかなり微妙です。C++11 スレッド ライブラリを使用すると、関数を呼び出してそのすべての引数を指定でき、これをスレッド セーフな方法で処理できます。もう渡す必要はありません。また、これらの引数用のストレージ スペースvoid *を使用mallocまたはnew作成する必要もありません。スレッドが必要とする引数をスレッド コンストラクターに直接渡すことができます。

実際、あなたのプログラムにはメモリリークがあります。指すスペースmallocを再利用することはありません。csock長時間実行すると、これらすべてのファイルハンドルのスペースが再利用されないため、最終的にメモリ不足になります。

プログラムにファイルハンドル リークがある可能性もあります。closeのソケットには表示されませんNetwork::SocketHandler。しかし、私はあなたのプログラム全体を把握していないので、それについては確信が持てません.

于 2013-01-18T18:20:51.490 に答える