Compiler error extending FRunnableThread

Compiler crashes when trying to extend class FRunnableThread

2>EXEC : error : Couldn't find parent type for 'ServerThread' named 'FRunnableThread' in current module or any other module parsed so far.
2>Error : Failed to generate code for RenderServerEditor - error code: OtherCompilationError (5)
2>  UnrealHeaderTool failed for target 'RenderServerEditor' (platform: Win64, module info: D:\Unreal_Projects\RenderServer\Intermediate\Build\Win64\RenderServerEditor\Development\UnrealHeaderTool.manifest).
2>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.MakeFile.Targets(38,5): error MSB3073: The command ""D:\UnrealEngine4\Epic Games\4.9\Engine\Build\BatchFiles\Build.bat" RenderServerEditor Win64 Development "D:\Unreal_Projects\RenderServer\RenderServer.uproject" -rocket -waitmutex" exited with code -1.

This is the code that crashes

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreGlobals.h"
#include "SocketServer.h"
#include "Object.h"
#include "ServerThread.generated.h"


/**
 * 
 */
UCLASS()
class RENDERSERVER_API UServerThread : public FRunnableThread;
{
	GENERATED_BODY()
	
	
	
	
};

Thanks in advance for the help :smiley:

I think what you want to do is to create a run-able that holds it’s own thread. If yes you should not inherit from FRunableThread, you have to use it. The next snippet is a sample implementation of a server that listens to connections on a separate thread.

// RunableServer.h
//
// Copyright (c) 2015 Moritz Wundke
// MIT License
//

#pragma once

#include "Networking.h"
#include "TcpListener.h"

// Default endpoint for the server
#define DEFAULT_ENDPOINT FIPv4Endpoint(FIPv4Address(127, 0, 0, 1), 5005)

/**
 * Server listening on a TCP socket
 */
class FRunableServer
    : public FRunnable
{
public:
    FUnrealEdRemoteServer();

    ~FUnrealEdRemoteServer();

    /** FRunnable init */
    virtual bool Init() override;

    /** FRunnable loop */
    virtual uint32 Run() override;

    bool HandleListenerConnectionAccepted(class FSocket* ClientSocket, const FIPv4Endpoint& ClientEndpoint);

    /**
    * Checks whether the listener is listening for incoming connections.
    *
    * @return true if it is listening, false otherwise.
    */
    bool IsActive() const
    {
        return (!Stopping);
    }

    virtual void Stop() override
    {
        Stopping = true;
    }

    virtual void Exit() override { }

private:
    class FTcpListener *Listener = NULL;

    /** Current clients and pending to get accepted clients */
    TQueue<class FSocket*, EQueueMode::Mpsc> PendingClients;
    TArray<class FSocket*> Clients;

    /** Used to tell that the thread is stopping */
    bool Stopping;

    /** Connection thread, used to not block the editor when waiting for connections */
    FRunnableThread* Thread = NULL;

    /** Basic message handling, your implementation will be in here */
    FString HandleClientMessage(const FSocket *Socket, const FString& Message);
};

And the CPP

// RunableServer.cpp
//
// Copyright (c) 2015 Moritz Wundke
// MIT License
//

#include "RunableServer.h"
#include "Runtime/Core/Public/Misc/CString.h"

FRunableServer::FRunableServer()
    : Listener(NULL), Thread(NULL)
{
    Thread = FRunnableThread::Create(this, TEXT("FRunableServer"), 8 * 1024, TPri_Normal);
}

FRunableServer::~FRunableServer()
{
    // Stop the runnable
    Stop();

    // Stop accepting clients first
    if (Listener != NULL)
    {
        Listener->Stop();
        delete Listener;
        Listener = NULL;
    }

    // Kill all pending connections and current connections
    if (!PendingClients.IsEmpty())
    {
        FSocket *Client = NULL;
        while (PendingClients.Dequeue(Client))
        {
            Client->Close();
        }
    }
    for (TArray<class FSocket*>::TIterator ClientIt(Clients); ClientIt; ++ClientIt)
    {
        (*ClientIt)->Close();
    }

    // And last but not least stop the main thread
    if (Thread != NULL)
    {
        Thread->Kill(true);
        delete Thread;
    }
}

bool FRunableServer::HandleListenerConnectionAccepted(class FSocket* ClientSocket, const FIPv4Endpoint& ClientEndpoint)
{
    PendingClients.Enqueue(ClientSocket);
    return true;
}

bool FRunableServer::Init()
{
    if (Listener == NULL)
    {
        Listener = new FTcpListener(DEFAULT_ENDPOINT);
        Listener->OnConnectionAccepted().BindRaw(this, &FUnrealEdRemoteServer::HandleListenerConnectionAccepted);
        Stopping = false;
    }
    return (Listener != NULL);
}

/** Send a string message over to a socket */
bool SendMessage(FSocket *Socket, const FString& Message)
{
    check(Socket);
    int32 BytesSent = 0;
    return Socket->Send((uint8*)TCHAR_TO_UTF8(*Message), Message.Len(), BytesSent);
}

/** Receive a string message from a socket */
bool RecvMessage(FSocket *Socket, uint32 DataSize, FString& Message)
{
    check(Socket);

    FArrayReaderPtr Datagram = MakeShareable(new FArrayReader(true));
    Datagram->Init(FMath::Min(DataSize, 65507u));

    int32 BytesRead = 0;
    if (Socket->Recv(Datagram->GetData(), Datagram->Num(), BytesRead))
    {
        char* Data = (char*)Datagram->GetData();
        Data[BytesRead] = '\0';
        Message = UTF8_TO_TCHAR(Data);
        return true;
    }
    return false;
}

uint32 FRunableServer::Run()
{
    while (!Stopping)
    {
        if (!PendingClients.IsEmpty())
        {
            FSocket *Client = NULL;
            while (PendingClients.Dequeue(Client))
            {
                Clients.Add(Client);
            }
        }

        // remove closed connections
        for (int32 ClientIndex = Clients.Num() - 1; ClientIndex >= 0; --ClientIndex)
        {
            if (Clients[ClientIndex]->GetConnectionState() != SCS_Connected)
            {
                Clients.RemoveAtSwap(ClientIndex);
            }
        }

        // Poll data from every connected client
        for (TArray<class FSocket*>::TIterator ClientIt(Clients); ClientIt; ++ClientIt)
        {
            FSocket *Client = *ClientIt;
            uint32 DataSize = 0;
            while (Client->HasPendingData(DataSize))
            {
                FString Request;
                if (RecvMessage(Client, DataSize, Request))
                {
                    FString Response = HandleClientMessage(Client, Request);
                    SendMessage(Client, Response);
                }
            }
        }

        FPlatformProcess::Sleep(0.2f);
    }

    return 0;
}

FString FRunableServer::HandleClientMessage(const FSocket *Socket, const FString& Message)
{
    bool bProcessed = false;
    FString Response;

    // TODO: Here goes your code to handle the actual message
    
    return bProcessed ? TEXT("OK") : TEXT("KO");
}

NOTE: The code might need some tweaks but you should see how I’m using the thread in here

Thank you very much for your help. It really helped me

Remember to accept the answer

I know this post has been closed over a year ago, but I just had a few questions and hoped you can answer them. How do you create this thread, and does this work for the multithreading part (also with closing the thread)?