简体   繁体   English

使用互斥量将一次运行的线程数限制为2

[英]Using a Mutex to Limit the Number of Threads Running at a Time to 2

I have a program that pushes 10 threads into a vector, each of which is supposed to print out a character 5 times before finishing ('A' for the first thread, 'B' for the second, etc). 我有一个程序,该程序将10个线程推入一个向量中,每个线程应该在完成之前打印出5次字符(第一个线程为'A',第二个线程为'B',依此类推)。 I'm able to get them to either run all at once (using detach()) or have them run one at a time (using join()). 我能够使它们要么一次运行全部(使用detach()),要么一次运行一次(使用join())。 Now I want to use a Mutex to limit the number of threads allowed to print at a time to 2. I've been able to declare the mutex and put the lock in place but I'm unsure of how to apply a limit like this. 现在,我想使用互斥锁将一次允许打印的线程数限制为2。我已经能够声明互斥锁并将锁放置在适当的位置,但是我不确定如何应用这样的限制。 Anyone have any ideas on how to proceed? 任何人都对如何进行有任何想法?

deque<int> q ;
mutex print_mutex ;
mutex queue_mutex ;
condition_variable queue_cond ;

void begin(int num) {
    unique_lock<mutex> ul {queue_mutex};
    q.emplace_back(num);
    queue_cond.wait(ul,[num]{
        return q.front() == num; });
    q.pop_front();
    cout << num << " leaves begin " << endl ;
}

void end ( int num ) {
    lock_guard<mutex>lg{queue_mutex};
    queue_cond.notify_all();
    cout << num << " has ended " << endl ;
}

void run(int num, char ch) {
    begin(num);
    for (int i = 0; i < 5; ++i) {
        {
            lock_guard<mutex> lg { print_mutex };
            cout << ch << endl << flush ;
        }
        sleep_for(milliseconds(250));
    }
    end(num);
}

int main() {
    vector<thread>threads {};
    for (int i = 0; i < 10; ++i) {
        threads.push_back(thread{run,i,static_cast<char>(65+i)});
        threads.at(i).join();
    }
}

You have already set up a FIFO for your threads with the global deque<int> q . 您已经使用全局deque<int> q为线程设置了FIFO。 So let's use that. 因此,让我们使用它。

Currently, you're trying to restrict execution until the current thread is at the front. 当前,您正在尝试限制执行,直到当前线程位于最前面。 Although there's a bug, because begin will immediately pop that thread from the deque. 尽管存在错误,但是因为begin将立即从双端队列中弹出该线程。 Better to remove the value when you call end . 最好在调用end时删除该值。 Here's that change, first: 首先是以下更改:

void end(int num)
{
    {
        lock_guard<mutex>lg{queue_mutex};
        cout << num << " has ended " << endl ;
        q.erase(find(q.begin(), q.end(), num));
    }
    queue_cond.notify_all();
}

This uses std::find from <algorithm> to remove the specific value. 它使用<algorithm> std::find删除特定值。 You could use pop_front , but we're about to change that logic so this is more generic. 您可以使用pop_front ,但是我们将更改该逻辑,因此更通用。 Also notice you don't need to lock the condition variable when you notify. 还要注意,通知时您不需要锁定条件变量。

So, it's not much of a stretch to extend the logic in begin to be in the first two places. 所以,这不是太大的舒展在延长的逻辑begin是在前两位。 Here: 这里:

void begin(int num)
{
    unique_lock<mutex> ul {queue_mutex};
    q.emplace_back(num);
    queue_cond.wait(ul,[num]{
        auto end = q.begin() + std::min(2, static_cast<int>(q.size()));
        return find(q.begin(), end, num) != end;
        });
    cout << num << " leaves begin " << endl ;
}

You can change that 2 to anything you want, allowing up to that many threads to pass. 您可以将2更改为所需的任何值,最多允许通过多个线程。 At some point, you would probably abandon this approach and use something simpler like a single counter variable, then rely on the thread scheduler to manage which thread is woken, rather than force them into your FIFO. 在某个时候,您可能会放弃这种方法,而使用诸如单个计数器变量之类的更简单的方法,然后依靠线程调度程序来管理唤醒了哪个线程,而不是将其强制进入FIFO。 That way you can switch to using notify_one to wake a single thread and reduce switching overhead. 这样,您可以切换到使用notify_one唤醒单个线程并减少切换开销。

Anyway, the last thing to do is remove the join from your thread generation loop. 总之,要做的最后一件事就是删除join您的线程生成循环。 The concurrency is now managed by begin and end . 并发现在由beginend管理。 So you would do this: 因此,您可以这样做:

for (int i = 0; i < 10; ++i) {
    threads.push_back( thread{run, i, 'A'+i} );
}
for (auto & t : threads) t.join();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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