Good mornind, I'm making a simple program to test how pthreads share variables (concretely std::string and char* variables). Yesterday I made a similar one but with integers, where I learnd the basics of Mutex and a few other things about pointers.
This program simmulates sending and receiving/storing the information of a file (because that's what I want to do after I fix this program), but I'm having some trouble when sharing std::strings between threads.
This is my program:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <mutex>
#include "./include/socket_c.h"
std::mutex m;
void *receive_mode(void* dir)
{ m.lock();
socket_c receive_socket(1026, "127.0.0.2");
Message receive_message{};
sockaddr_in send_address{};
send_address = make_ip_address(1025, "127.0.0.1");
m.unlock();
receive_socket.receive_from(receive_message, send_address);
m.lock();
std::string d = *static_cast<std::string*>(dir);
std::cout << "SAVED IN " << d << " : " << receive_message.text << std::endl;
m.unlock();
}
void *send_mode(void* name)
{ m.lock();
sockaddr_in receive_address{};
receive_address = make_ip_address(1026, "127.0.0.2");
socket_c send_socket(1025, "127.0.0.1");
Message send_message{};
strcpy(send_message.text, "Este es un mensaje enviado");
send_socket.send_to(send_message, receive_address);
std::string n = *static_cast<std::string*>(name);
std::cout << "READ FROM " << n << " : " << send_message.text << std::endl;
m.unlock();
}
int main(void)
{ pthread_t receive_t, send_t;
char c1[30];
std::string c2;
while(true)
{ std::cout << "Option [send | receive]: ";
std::cin >> c1;
if (strcmp(c1, "receive") == 0)
{ std::cout << "Directory: ";
std::cin >> c2;
pthread_create(&receive_t, nullptr, receive_mode, &c2);
}
else if (strcmp(c1, "send") == 0)
{ std::cout << "File: ";
std::cin >> c2;
pthread_create(&send_t, nullptr, send_mode, &c2);
pthread_join(receive_t, nullptr);
}
}
}
I'm using UDP sockets here because I'm more familiar with them. But the problem here aren't the sockets per se. The input/output should be the following:
Option [send | receive]: receive
Directory: DESTINY_DIRECTORY
Option [send | receive]: send
File: SOURCE_FILE
Read from SOURCE_FILE : This is the sent message
Saved in DESTINY_DIRECTORY : This is the sent message
Option [send | receive]: ^C
Notice that the content of the std::strings displayed in each function should be different. But this the real input/output:
Option [send | receive]: receive
Directory: DESTINY_DIRECTORY
Option [send | receive]: send
File: SOURCE_FILE
Read from SOURCE_FILE : This is the sent message
Saved in SOURCE_FILE : This is the sent message
Option [send | receive]: ^C
Here it keeps the value of the std::string I pass as an argument for the two differnt functions executed in different threads.
I know this all has to do with how pthreads manage memory, but don't know what is causing this or how to solve it.
EDIT 1: It turns out that I was reusing the same pointer in void* send_mode(void*) and in void* receive_mode(void*). Passing different std::string variables to the different pthreads solves the problem.
I'm leaving socket-related code here in case that you want to test my program.
SOCKETS
#ifndef NETCP_SOCKET_C_H_
#define NETCP_SOCKET_C_H_
#define MSG_SIZE 512
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <sys/socket.h>
struct Message
{ char text[MSG_SIZE]; // Content of the message.
int size; // Total size of the information if it's composed of various Message structs.
};
class socket_c
{ private:
int fd_;
public:
socket_c(short, const std::string&);
~socket_c(void);
int get_fd(void) const;
// Functions for sending and receiving messages.
int send_to(const Message& message, const sockaddr_in& address) const;
int receive_from(Message& message, sockaddr_in& address) const;
};
#endif
// Given a port number and a std::string containing a valid IP address,
// creates a socket and an address and associate them with bind().
socket_c::socket_c(short port, const std::string& ip_address)
{ fd_ = socket(AF_INET, SOCK_DGRAM, 0);
if (check_success(fd_, "No se pudo crear el socket. ") == 1) return;
sockaddr_in address = make_ip_address(port, ip_address);
int bnd = bind(fd_, (const sockaddr*)& address, sizeof(address));
}
socket_c::~socket_c(void) { close(fd_); }
int socket_c::get_fd(void) const { return fd_; }
int socket_c::send_to(const Message& message, const sockaddr_in& address) const
{ int result = sendto(fd_, &message, sizeof(message), 0, reinterpret_cast<const sockaddr*>(&address), sizeof(address));
return check_success(result, "No se pudo enviar el mensaje. ");
}
int socket_c::receive_from(Message& message, sockaddr_in& address) const
{ socklen_t src_len = sizeof(address);
int result = recvfrom(fd_, &message, sizeof(message), 0, reinterpret_cast<sockaddr*>(&address), &src_len);
return check_success(result, "No se pudo recibir el mensaje. ");
}