线程C++中的瓶颈
Bottleneck in Threads C++
所以我只是想验证我的理解,并希望你们能够消除任何误解。因此,本质上,我有两个线程,它们使用相同的锁,并在持有锁时执行计算,但有趣的是,在锁内,我会导致线程短时间睡眠。对于这两个线程,任何一个线程的睡眠时间都会略有不同。由于锁的工作方式,速度较快的线程是否会被速度较慢的线程阻塞,因为它必须等待它完成?
例如:
Thread1() {
lock();
usleep(10)
lock();
}
-
Thread2() {
lock();
sleep(100)
lock();
}
现在,由于Thread2保持锁的时间更长,这将导致瓶颈。可以肯定的是,这个系统应该有一个关于谁得到锁的来回发生,对吧?
应该是:
Thread1 gets lock
Thread1 releases lock
Thread2 gets lock
Thread2 releases lock
Thread1 gets lock
Thread1 releases lock
Thread2 gets lock
Thread2 releases lock
等等,对吧?线程1应该永远无法在释放锁之后立即获取锁,对吗?
线程1应该永远无法在释放锁之后立即获取锁,对吗?
否,线程1可以在释放锁之后立即重新获取锁,因为线程2仍然可以被挂起(由于调度程序而休眠)
此外,sleep
仅保证线程将睡眠至少所需的量,它可以而且通常会更多。
在实践中,在计算值时您不会持有锁,您会获得锁,获得计算所需的值,解锁,计算它,然后再次获得锁,检查计算的旧值是否仍然有效/需要,然后存储/返回计算结果。为此,发明了std::future
和原子数据类型。
这个系统应该有一个来回发生谁得到锁,对吧?
大多数情况下大多数时候是来回的,但有时Thread1可能会有两个锁定/解锁周期。这取决于您的调度程序,任何执行和周期都可能有所不同。
绝对没有什么可以阻止任何一个线程在释放锁后立即重新获取锁。我不知道你认为是什么阻止了这种情况的发生,但没有什么可以。
事实上,在许多实现中,已经运行的线程在获取锁方面比必须准备运行的线程具有优势。这是一个合理的优化,可以最大限度地减少上下文切换。
如果你把睡眠作为一种模拟工作的方式,并认为这代表了锁公平的一些现实世界问题,那么你错了。睡眠的线程会自动产生剩余的时间片,并且与耗尽时间片进行工作的线程的处理方式非常不同。如果这些线程真的在工作,最终一个线程会耗尽它的时间片。
根据您试图实现的目标,有几种可能性。
如果您希望线程按特定顺序运行,请查看此处。基本上有两个选项:
-一种是使用事件,其中一个线程向下一个线程发出信号,它已经完成了自己的工作,因此下一个可以启动
-另一种是有一个调度程序线程来处理事件或信号量的排序。
如果你希望你的线程独立运行,但有一个锁机制,其中试图获得锁的顺序是保留的,你可以看看这里。答案的最后一部分使用每个线程一个条件变量的队列似乎很好。
正如之前的回答和评论中所说,用睡眠来安排日程是个坏主意。此外,锁只是一种互斥机制,对执行顺序没有任何保障。锁通常用于防止对关键资源的并发访问,所以它应该这样做。临界截面越小越好
最后,是的,试图订购线程会造成"瓶颈"。在这种特殊的情况下,如果所有的计算都是在锁定的部分中进行的,那么线程将不会并行执行任何操作,因此您可能会质疑使用线程的实用性。
编辑:
还有一个警告:要小心,对于线程,这并不是因为它在你的机器上工作了10次(按照你想要的计划),它总是会工作的,尤其是当你更改任何上下文(机器、工作负载…)时。你必须通过设计来确保它。
- 从不同线程使用int64的不同字节安全吗
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 在C++中使用cURL和多线程
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在cuda线程之间共享大量常量数据
- 如何将元素添加到数组的线程安全函数?
- 线程,如果else语句,都是错误的上下文切换后,会发生什么
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- 异常属于C++中的线程还是进程
- C++中的线程安全删除
- C++使用params创建线程函数会导致转换错误
- 类与私有变量的其他类之间的线程安全性
- CoInitialize()在单独的线程上崩溃而不返回
- c++中的线程池
- 线程之间的布尔停止信号
- 为什么std::async使用同一个线程运行函数
- 用于矢量处理的多个线程
- C++为线程工作动态地分割例程
- 为什么我不能在 while 循环中创建线程?