繁体   English   中英

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

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

我有一个程序,该程序将10个线程推入一个向量中,每个线程应该在完成之前打印出5次字符(第一个线程为'A',第二个线程为'B',依此类推)。 我能够使它们要么一次运行全部(使用detach()),要么一次运行一次(使用join())。 现在,我想使用互斥锁将一次允许打印的线程数限制为2。我已经能够声明互斥锁并将锁放置在适当的位置,但是我不确定如何应用这样的限制。 任何人都对如何进行有任何想法?

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();
    }
}

您已经使用全局deque<int> q为线程设置了FIFO。 因此,让我们使用它。

当前,您正在尝试限制执行,直到当前线程位于最前面。 尽管存在错误,但是因为begin将立即从双端队列中弹出该线程。 最好在调用end时删除该值。 首先是以下更改:

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();
}

它使用<algorithm> std::find删除特定值。 您可以使用pop_front ,但是我们将更改该逻辑,因此更通用。 还要注意,通知时您不需要锁定条件变量。

所以,这不是太大的舒展在延长的逻辑begin是在前两位。 这里:

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 ;
}

您可以将2更改为所需的任何值,最多允许通过多个线程。 在某个时候,您可能会放弃这种方法,而使用诸如单个计数器变量之类的更简单的方法,然后依靠线程调度程序来管理唤醒了哪个线程,而不是将其强制进入FIFO。 这样,您可以切换到使用notify_one唤醒单个线程并减少切换开销。

总之,要做的最后一件事就是删除join您的线程生成循环。 并发现在由beginend管理。 因此,您可以这样做:

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