简体   繁体   中英

std::thread when is thread executed?

I've ran through some threading tutorials but am curious about one thing.

std::thread Child([](){ std::cout << "When am I executed?" << std::endl << std::endl; });

//Some other code

Child.join();

//I'm guessing now my thread would be running

Is the thread being executed when I call join() or is it being run sometime between when create the thread and when I call join? If it is executed when join() is called, just to check my understanding, it tells that portion to execute and your program continues on the main thread and eventually the child thread has done some work on the same memory the main thread is using?

If I wanted to create a wrapper for a generic class, I would want to do something like below but I can't seem to figure it out completely. I'm confused with managing the threads in terms of memory.

class Sync {
private:
    int val;

public:
    Sync() : val(0) {}
    void Inc() {val++}
    int Value() { return val; }
};

class Async {
private:
    Sync Foo;
    std::mutex mtx;
    std::vector<std::thread*> Children;
public:
    //I would need a new thread each time I called Inc
    void Inc() { 
        Children.push_back(new std::thread([&]() {
            mtx.lock();
            Foo.Inc();
            mtx.unlock();
        }));


    }
    //But how do I know when it is safe to delete Child?  
    int Value() { 
        for(auto& thds : Children) {
            thds->join();
            delete thds; 
        }
        Children.clear();
        return Foo.Value(); }
};

I was considering that an appropriate location might be at the end of the thread function because Child would no longer be needed but what happens if you try to destroy the thread from within itself? I'm guessing it will be as much of a bad idea as it sounds. How can I know when it's okay to delete my thread? Is there a better approach?

Modified above code to reflect suggestions from below.

I now realize what the tutorials were talking about in regards to throwing an exception so I should use a mutex guard and not mtx.lock() I guess.

The purpose of join is to, essentially, wait for the thread to complete. So once Child->join(); returns, your thread has completed. Of course, you could also do Child->join() in the destructor [or at some other point, just make sure it is called at some point].

Note that, the thread will start running at some point between the time it actually created, and the end of join. There is no way of telling when that will happen. If you have lots of threads already running on the system, the time will be distributed between all threads, and your thread may not run for several seconds. On the other hand, if there is a CPU sitting there "twiddling it's fingers", it could quite possibly start before the main thread is out of the new std::thread(...) construction [because std::thread won't return until the thread has been properly created, and some data is being stored in the thread object, so the thread may well have completed by the time you get to Child->join() . There is no way to tell which of these options it is without knowing what state the system is in.

The operating system matters, but it is rather universal. The thread gets scheduled to execute. When the operating system gets around to actually make it run is entirely unpredictable. You'll have decent odds for "quickly" on a machine with multiple cores, universally available today.

thread::join() just ensures that the thread finished executing. You would never actually write code like this, it is completely pointless to start a thread and then wait for it to complete. Might as well execute the thread's code directly. Same outcome without bogging down the operating system with creating a thread.

You cannot know in which order or on which core your thread will be run.

A posix thread is basically treated by linux as a process sharing its heap with another one. The kernel will schedule them and decide which core to use. For instance look at the generated (protected) assembly you will not see any "multicore/multithread programming", as this is done at kernel level.

This is why function such as join, and artifacts such as mutex/semaphores exists. To take care of race condition and other related stuffs.

Is the thread being executed when I call join() or is it being run sometime between when create the thread and when I call join?

The thread is executed (started) after you create the thread, depending on the available resources that might take some time. The join() method waits(blocks) until the thread has finished its work.

A suggestion: i would not name the variable to the Sync object This , its confusing, since there exists the this keyword.

You can safely delete the std::thread object after calling join() in Async::Inc() , plus you don't need to store the reference as a member variable, it's only used in that function.

You might also take a look at the <atomic> header, std::atomic<int> or std::atomic_int .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM