Controlling parallel jobs with condition_variable
Overall
Unfortunately your code is broken.
The main thread can potentially call notify_all() twice before any of the threads are released from the first call wait(lock). Say I hit return several time very quickly.
It's even possible for the main thread to call notify_all() before any of  the children call wait(lock) the first time (what happens if I pipe a file into standard in).
If you want all threads and the main to wait and sync at a common point you must explicitly create what is called a sync barrier. This is usually done by having a variable that counts the threads that have reached the sync point and only allowing progress after all threads have reached it and decremented the counter to the point where it reaches 0.
To avoid confusion you will also need to use a separate condition_variable for sync and start points.
Finally this code will never finish.
for (auto&amp; job : jobs) { job.join(); }

Waits for all the threads to finish. But none of the jobs ever exit the callback function work().
Note: you can't just remove this line. A thread who's destructor is called before the thread of execution finishes its work will generate an exception that causes the application to quit. So you should call join() on all threads to verify that the thread of execution has completed.
Design.
I understand the need to force all the children thread to wait at an initial sync point. They need to verify that the main thread has successfully initialized all the global state.
But after that each worker thread does not need to wait at a sync point (unless there is an application requirement to do so). It just needs to wait for work to become available grab it then do it. Once the work is done it is usual for a thread to check if there is more work available (as creating threads is rather expensive you usually don't want to create and destroy threads regularly). If no work is available then make it wait on a condition variable until there is work.
All threads should periodically check to see if they are still needed and expire when they are no longer required. Thus allowing the main thread to exit.
Simple Code Review
Global variables a re a bad idea.
std::mutex mx;
std::condition_variable global;
bool start = false;
bool ready = false;
std::map&lt;int, std::atomic&lt;bool&gt;&gt; status;

wrap all this up in a class that you can then use locally inside a function.
Don't do this.
using namespace std;

If your code is more than 10 lines long you are going to cause issues sooner or later. See: Why is “using namespace std;” considered bad practice?
Threaded job Queue.
The following is a generalized job queue.
Now I read in your question that you need to have work done in synchronized bursts. This class does not do that but with some small adjustments that can be done.
void JobQueue::jobWorker()
{
    while(true)
    {
        auto job = getWork();
        if (job.execute())
        {
            // Indicate a thread should exit by returning true from execute.
            break;
        }
    }
}

class JobQueue
{
    private:
       void jobWorker();
    public:

        // Both addWork()/getWork() modify internal state.
        // So calls must be synchronized via locks.
        template&lt;typename F&gt;
        void addWork(F&amp;&amp; work); // Adds a job to an internal queue.           
        Job getWork();          // If no work is available will cause the
                                // thread to wait (on a condition variable)
                                // until there is work available.



         // Constructor initializes all internal state.
         // Then creates `count` threads of execution that call jobWorker.
         JobQueue(int count);

         // The destructor waits for all work (added via addWork())
         // to be finished.
         //
         // This means it must:
         // 1) wait for the work queue to drain.
         // 2) all threads must be given a job that will return true.
         //    This will allow all the worker threads to exit.
         // 3) Wait for all worker threads by calling join() on them.
         ~JobQueue();           
};

Then main is simplified too:
int main()
{
    JobQueue    jobQueue(4);  // not much point it making this number
                              // larger than the number of cores available
                              // on your machine. Actually you can get a default
                              // value that is the number of cores.

    // Call addWork() as many times as required.
    for(int loop = 0;loop &lt; 1'000'000;++loop) {
        jobQueue.addWork([](){std::cout &lt;&lt; &quot;Some Work\n&quot;;sleep(5);});
    }
}