[C++] Problema con le thread

mirko.saggioro
Ciao a tutti :) ho da poco iniziato a fare esercizi sulle thread ed ovviamente ho i primi problemi :(
Devo svolgere questo semplice esercizio dove ho un buffer, in cui devo inserire dei dati presi da un file input_file.txt, ad esempio questo:
1
2
3
4
Questi dati poi vengono letti e inseriti nel buffer con la funzione lettura_posizione e poi vengono letti e scritti a terminale con la funzione scrittura_posizione, il tutto gestendo l'accesso al buffer.
Questo è il buffer:
// Buffer.h

#ifndef Buffer_h
#define Buffer_h

#include <queue>
using std::queue;
#include <mutex>
using std::mutex;
#include <condition_variable>
using std::condition_variable;

class Buffer
{
    public:
        void append(double v);
        double take();

    private:
        queue<double> buffer_;
        mutex mutex_;
        condition_variable not_empty_;       
};

void lettura_posizione(Buffer buf);
void model(Buffer buf);

#endif

//Buffer.cpp
#include <iostream>
using std::cout;
using std::endl;
#include <fstream>
using std::ifstream;
#include <string>
using std::string;
#include <mutex>
using std::mutex;
using std::unique_lock;
#include <condition_variable>
using std::condition_variable;

#include "Buffer.h"

void Buffer::append(double shift)
{
    unique_lock<mutex> mlock(mutex_);
    buffer_.push(shift);
    not_empty_.notify_one(); //signalC
}

double Buffer::take()
{
    unique_lock<mutex> mlock(mutex_);
    while(buffer_.empty())
        not_empty_.wait(mlock); //waitC
    double posit =buffer_.front();
    buffer_.pop();
    return posit;
}

void lettura_posizione(Buffer buf)
{
    //Prendo i dati di input da un file txt
    ifstream input("input_file.txt");
        if(!input.is_open())
    {
        cout << "Unable to open the input file." << endl;
        exit(EXIT_FAILURE);
    }
	string line;
	while (getline (input, line)){
        size_t pos = line.find_first_of(" ",0);
        double position = stod(line.substr(pos+1,line.size()));
        buf.append(position);
    }
}

void scrittura_posizione(Buffer buf)
{
    for(int i=0; i<4; i++){
            double pos= buf.take();
            cout<<pos<<endl;
    }
}


E il main è questo:
#include <iostream>
using std::cout;
using std::endl;
#include <thread>
using std::thread;


#include "Buffer.h"

Buffer b1;

int main(int argc, char* argv[])
{
    thread lettura{lettura_posizione, b1};
    thread scrittura{scrittura_posizione, b1};

    lettura.join();
    scrittura.join();
    
    cout << "End of main thread." << endl;

    return 0;
}

Il problema è che quando compilo mi esce questo errore:
In file included from main.cpp:4:
/usr/include/c++/9/thread: In instantiation of ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(Buffer); _Args = {Buffer&}; <template-parameter-1-3> = void]’:
main.cpp:47:41:   required from here
/usr/include/c++/9/thread:120:44: error: static assertion failed: std::thread arguments must be invocable after conversion to rvalues
  120 |           typename decay<_Args>::type...>::value,
      |                                            ^~~~~
/usr/include/c++/9/thread: In instantiation of ‘struct std::thread::_Invoker<std::tuple<void (*)(Buffer), Buffer> >’:
/usr/include/c++/9/thread:131:22:   required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(Buffer); _Args = {Buffer&}; <template-parameter-1-3> = void]’
main.cpp:47:41:   required from here
/usr/include/c++/9/thread:243:4: error: no type named ‘type’ in ‘struct std::thread::_Invoker<std::tuple<void (*)(Buffer), Buffer> >::__result<std::tuple<void (*)(Buffer), Buffer> >’
  243 |    _M_invoke(_Index_tuple<_Ind...>)
      |    ^~~~~~~~~
/usr/include/c++/9/thread:247:2: error: no type named ‘type’ in ‘struct std::thread::_Invoker<std::tuple<void (*)(Buffer), Buffer> >::__result<std::tuple<void (*)(Buffer), Buffer> >’
  247 |  operator()()
      |  ^~~~~~~~


Qualcuno sa dove sbaglio e può aiutarmi? Grazie :D

Risposte
Quinzio
Allora, il problema e' tedioso da capire e da comprendere.
Anche per me comunque sono argomenti in parte oscuri.

Comunque, provo a spiegartelo.
La classe thread sostanzialmente lancia la funzione che tu gli hai impostato, con i suoi argomenti.
Ora, gli argomenti sono passati facendo il forward di un reference.
Questa espressione oscura significa che devi passargli un puntatore alla classe Buffer e non l'oggetto stesso, il Buffer b1 ad esempio.
Questo perche' l'oggetto potrebbe ancora non esistere al momento della creazione del thread, ma esistere quando viene lanciato.
La conclusione e' che bisogna usare un reference, come ti faccio vedere nel codice che copio.
Vedi che ad es. una delle funzioni del thread cambia cosi':
void scrittura_posizione(Buffer &buf)

In ogni caso, a parte l'errore che da il compilatore, il fatto che tu non abbia usato dei puntatori ma hai passato alla funzione l'oggetto stesso, e' un errore grave e mostra che non hai compreso bene come avviene il passaggio degli argomenti (per value o per reference) e cosa comporta cio' nel caso che l'argomento sia un oggetto.

Ti lascio alcuni link che sicuramente spiegano il tutto molto meglio di come farei io.
https://stackoverflow.com/questions/619 ... e-after-co
https://stackoverflow.com/questions/147 ... -parameter
e poi ti basta cercare su Google.

// Buffer.h

#ifndef Buffer_h
#define Buffer_h

#include <queue>
using std::queue;
#include <mutex>
using std::mutex;
#include <condition_variable>
using std::condition_variable;

class Buffer
{
    public:
        void append(double v);
        double take();

    private:
        queue<double> buffer_;
        mutex mutex_;
        condition_variable not_empty_;
};

void lettura_posizione(Buffer &buf);
void scrittura_posizione(Buffer &buf);
void model(Buffer buf);

#endif

//Buffer.cpp
#include <iostream>
using std::cout;
using std::endl;
#include <fstream>
using std::ifstream;
#include <string>
using std::string;
#include <mutex>
using std::mutex;
using std::unique_lock;
#include <condition_variable>
using std::condition_variable;

#include "Buffer.h"

void Buffer::append(double shift)
{
    unique_lock<mutex> mlock(mutex_);
    buffer_.push(shift);
    not_empty_.notify_one(); //signalC
}

double Buffer::take()
{
    unique_lock<mutex> mlock(mutex_);
    while(buffer_.empty())
        not_empty_.wait(mlock); //waitC
    double posit =buffer_.front();
    buffer_.pop();
    return posit;
}

void lettura_posizione(Buffer &buf)
{
    //Prendo i dati di input da un file txt
    ifstream input("input_file.txt");
        if(!input.is_open())
    {
        cout << "Unable to open the input file." << endl;
        exit(EXIT_FAILURE);
    }
   string line;
   while (getline (input, line)){
        size_t pos = line.find_first_of(" ",0);
        double position = stod(line.substr(pos+1,line.size()));
        buf.append(position);
    }
}

void scrittura_posizione(Buffer &buf)
{
    for(int i=0; i<4; i++){
            double pos= buf.take();
            cout<<pos<<endl;
    }
}


// main.cpp
#include <iostream>
using std::cout;
using std::endl;
#include <thread>
using std::thread;


#include "Buffer.h"

Buffer b1;

int main(int argc, char* argv[])
{
    thread lettura(lettura_posizione, std::ref(b1));
    thread scrittura(scrittura_posizione, std::ref(b1));

    lettura.join();
    scrittura.join();

    cout << "End of main thread." << endl;

    return 0;
}



mirko.saggioro
Grazie!

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.