mercredi 30 mars 2016

Starting c++11 thread with a lambda capturing local variable

I have a rather basic problem and not sure where it originates from: lambda capture evaluation in a concurrent environment or misuse of boost filesystem library.
This is sample code:

#include <iostream>
#include <vector>
#include <thread>
#include <boost/filesystem.hpp>

using namespace std;
using namespace boost::filesystem;

void query(const string filename)
{
    cout << filename << " ";
}

int main() {
    path p("./");
    vector<thread> thrs;

    for(auto file = directory_iterator(p); file != directory_iterator(); ++file)
    {
        thread th( [file] {query(file->path().string());} );
        thrs.push_back(move(th));
    }

    for (auto& t : thrs)
        t.join();

    return 0;
}

which at runtime gives:

:~/workspace/sandbox/Release$ l
main.o  makefile  objects.mk  sandbox*  sources.mk  subdir.mk
:~/workspace/sandbox/Release$ LD_LIBRARY_PATH=$http://LD_LIBRARY_PATH:/home/a/custom-libs/boost-1_59/lib/ ./sandbox 
./subdir.mk ./sources.mk ./sandbox ./objects.mk ./main.o ./main.o

Notice the race condition - not all files end up being passed to thread function (at this run makefile is missing).
I am able to find a workaround by extracting the argument in a local var, rewriting the loop body as:

    auto fn = file->path().string();
    thread th( [fn] {query(fn);} );
    thrs.push_back(move(th));

Where is the race condition coming from?
Isn't file->path().string() evaluated right at the time of thread creation?

Aucun commentaire:

Enregistrer un commentaire