[英]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
. 并发现在由
begin
和end
管理。 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.