Thread in c ++ compilation error

1

I'm starting with threads and I've been following several steps and I think it's all right, but when it comes to executing it, it gives me error . The code:

    int main() {
    int num_it, num_threads,energy=50000;
    string sequence;
    cout << "Enter number of iterations: ";
    cin >> num_it;
    cout << endl << "Enter number of threads: ";
    cin >> num_threads;

    //thread* t = new thread[num_threads]; ---> Intento con array
    vector<thread> t; // Con vectores
    string* seq = new string[num_threads];
    for (int j = 0;j < num_it;j++) {
        for (int i = 0;i <= num_threads;i++) {
            seq[i] = gen_seq();
            t.push_back(thread(function_E, seq[i], sequence, energy));
        }
        int i = 5;

        for (auto &tt : t) { tt.join(); }
        for (int i = 0;i <= num_threads;i++) {
            seq[i].clear();
        //  t[i].join();
        }
    }
    cout << energy << endl << sequence << endl;
    system("pause");
    return 0;
}

and the function that I call in the threads:

    void function_E(string temp_seq,string &good_seq,int &energy) {
    int i = 1;
    int e = 0;

    //string seq = gen_seq();
    static mutex m;

    for (i = 1;i <= L - 1;i++) {

        e = e + (function_c(i, temp_seq)*function_c(i, temp_seq));
    }

    if (e < energy) {
        m.lock();
        energy = e;
        good_seq = temp_seq;
        m.unlock();

        }

}

The truth is that I do not know what the error is, I've tried everything ... This is made with VS2015, in case it's any good. Thank you in advance for the help.

    
asked by Lolo 13.10.2016 в 17:07
source

2 answers

1

Your error is that the std::thread do not support the step by reference, although you can simulate it:

t.push_back(std::thread(function_E, seq[i], std::ref(sequence), std::ref(energy)));

std::ref returns an object of type std::reference_wrapper<T> that is an object copiable and assignable, convertible to T& , hence you do not need to change the parameters of the function.

It is a non-invasive way to pass references through copyable objects.

    
answered by 15.10.2016 / 16:46
source
2

Before answering you, a couple of suggestions:

This:

string* seq = new string[num_threads];

It would look much better this way:

std::vector<std::string> seq;
seq.reserve(num_threads);

Among other things, you have forgotten to put the corresponding delete[] , which implies memory leaks and with this design you can save it.

With the theme of the life of the variables, his is to minimize the same to the essential minimum. This:

int i = 1;
// ...

for (i = 1;i <= L - 1;i++) {
  e = e + i;
}

It should be such that:

for(int i=1; i<L; i++){
  e += i;
}

And well, comment on your error that the threads do not support functions with references. The constructor of std::thread creates a copy of the parameters and calls them to the function that you indicate, so using references will not allow you to update these values.

To return values there are several options. My favorite are the futures. std::future is a mechanism that allows you to create asynchronous calls. With std::future we can attend other tasks until our asynchronous execution returns a result, at which time we can recover it and continue with our needs.

One of the cleanest ways I have found to do this is the one I comment on below.

First we create a structure that encapsulates the task to be executed asynchronously (for this we can use the function operator). In addition to this the class must store a member of type std::promise . This class is the one that is going to connect with std::future to indicate that there is already a result available:

struct CodigoPesado
{
  std::promise<int> promise;

  void operator()()
  {
    // Código pesado

    // Devolvemos el resultado de nuestra función
    promise.set_value(2);
  }
};

Now we create an instance of this class and we ask for a std::future :

CodigoPesado codigoPesado;
std::future<int> future = codigoPesado.promise.get_future();

We can now execute our task asynchronously:

std::thread hilo(std::ref(codigoPesado));

The wait can be done in two ways: active or passive.

Active wait:

std::chrono::milliseconds espera(100);
while( future.wait_for(espera) == std::future_status::timeout )
  std::cout << '.' << std::flush;

Passive waiting:

// La ejecución se quedará esperando en esta llamada hasta que el resultado
// esté listo
future.wait();

And finally we recover the value:

int valor = future.get();
std::cout << valor << '\n';

To incorporate this into your code you can create a structure, it would be worthwhile for std::future to return a std::tuple or a std::pair .

std::future<std::tuple<std::string,int>> future;

// Sobreescribimos los valores de sequence y energy
std::tie(sequence,energy) = future.get();

NOTE: std::future does not allow calls to the copy constructor (except for move syntax) or multiple calls to get() . To make use of this functionality it is necessary to resort to std::shared_future .

Of course you can also choose to save the management of std::thread and use std::async . It's cleaner and gives you a future automatically:

std::tuple<std::string,int> function_e(...);

std::future<std::tuple<std::string,int>> future
  = std::async(std::launch::async,function_E,...);
std::tie(sequence,energy) = future.get();

The hit of std::async , is that its use by default is not asynchronous but synchronous (I ignore the reasons), so if you do not put std::launch_async the execution will be totally synchronous.

Greetings.

    
answered by 13.10.2016 в 18:08