Hi, I am trying to make a simple chat for a game I am working at. The idea is to have one thread running the game itself, and maybe sending chat messages, and another only for receiving chat messages. I created a simple class called Chat which has two functions, one called add_string( std::string s ) and the other render().
The problem is that when trying to use add_string from the receiving thread, called "server" in my program it doesn't work properly. I have tried to use std::mutex to ensure the Chat object is not used simultaneously by the two threads. What happens is that the Chat object does not get the correct string but instead only parts of it or in most cases, an empty string. There is a third thread in this example program, the one called "client", used only to send messages. The Chat class works fine itself and so does the network parts of this program, so I figured the problem must be thread related
. So why is the "server" thread not able to properly add string objects to the chat object? Here's the code:
class Chat {
private:
const static int MAX_LINES = 25;
int linewidth;
sf::IntRect size;
sf::Font font;
sf::Text tempText;
std::deque<sf::Text> chatlog;
public:
Chat();
void add_string( std::string s );
void render();
};
// Chat.cpp
Chat::Chat() {
linewidth = 20;
size.height = SCREEN_HEIGHT;
size.width = SCREEN_WIDTH / 2;
size.top = 0;
size.left = SCREEN_WIDTH / 2;
if (!font.loadFromFile("times.ttf"))
{
// error...
//return 0;
}
tempText.setFont(font);
tempText.setCharacterSize(15);
tempText.setColor(sf::Color::White);
tempText.setStyle(sf::Text::Bold );
}
void Chat::add_string( std::string s ) {
// Move all other strings one line up.
for( auto it = chatlog.begin(); it < chatlog.end(); it++ ) {
sf::Vector2f temp = it->getPosition();
temp.y -= linewidth;
it->setPosition( temp );
}
// Add the new string to the bottom of the chat.
tempText.setString( s );
int xPos = size.left;
int yPos = size.top + size.height - linewidth;
tempText.setPosition( sf::Vector2f( xPos, yPos ) );
chatlog.push_back( tempText );
if( chatlog.size() > MAX_LINES ) {
chatlog.pop_front();
}
}
void Chat::render() {
for( auto it = chatlog.begin(); it < chatlog.end(); it++ ) {
window.draw( *it );
}
}
#include <iostream>
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Network.hpp>
#include <SFML/Graphics.hpp>
#include "globals.h"
#include "chat.h"
#include <string>
#include <thread>
#include <mutex>
bool quit = false;
#define SERVER_PORT 54000
#define CLIENT_PORT 54001
#define EXIT_PORT 54002
void server( Chat* p );
void client();
int apa = 0;
std::mutex chatMutex;
int main(int argc, char* argv[])
{
Chat chat;
chat.add_string( "BLALBALBLAL LBLBLABLABL " );
chat.add_string( "BLALBALGKDSGKSgBLAL LBLBLABLABL " );
chat.add_string( "CPMONGOBLABL " );
std::thread myClientThread( client );
std::thread myServerThread( server, &chat );
sf::UdpSocket socket;
//// bind the socket to a port
if ( socket.bind( EXIT_PORT ) != sf::Socket::Done )
{
// error...
}
sf::IpAddress recipient = sf::IpAddress::getLocalAddress();
char data[10] = "Byebye!";
while( !quit ) {
window.clear(sf::Color::Black);
chatMutex.lock();
chat.render();
chatMutex.unlock();
window.display();
}
myServerThread.join();
myClientThread.join();
return 0;
}
void client() {
sf::UdpSocket socket;
// bind the socket to a port
if (socket.bind( CLIENT_PORT ) != sf::Socket::Done)
{
// error...
}
char enteredIP[20];
std::cout << "Enter the IP you want to connect to" << std::endl;
std::cin.getline( enteredIP, 20 );
std::cout << enteredIP << std::endl;
sf::IpAddress recipient = enteredIP;
unsigned short port = SERVER_PORT;
while( !quit ) {
sf::Packet packet;
std::string input;
std::getline( std::cin, input );
packet << input;
if (sf::Keyboard::isKeyPressed( sf::Keyboard::Return ) ) {
if (socket.send(packet, recipient, port) != sf::Socket::Done) {
// error...
}
sf::Time t = sf::milliseconds( 500 );
sf::sleep( t );
}
}
}
void server( Chat* p ) {
sf::UdpSocket socket;
// bind the socket to a port
if ( socket.bind( SERVER_PORT ) != sf::Socket::Done )
{
// error...
}
sf::IpAddress sender;
unsigned short port;
while( !quit ) {
sf::Packet packet;
std::string receivedString;
if ( socket.receive( packet, sender, port ) != sf::Socket::Done ) {
// error...
}
packet >> receivedString;
chatMutex.lock();
p->add_string( receivedString );
chatMutex.unlock();
}
}