Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

c++ - Problem with pthreads and how they manage my std::string variables

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. ");
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
等待大神答复

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...