我正在使用在 ARM(而不是英特尔处理器)上运行的代码。从http://www.cplusplus.com/reference/condition_variable/condition_variable/wait_for/运行 c++11 代码示例(代码 A)来测试 wait_for() 机制。这不起作用 - 看起来 wait_for() 不等待。在英特尔工作得很好。经过一些研究并直接使用 pthread 库并设置 MONOTONIC_CLOCK 定义,解决了问题(代码 B)。(在ARM上运行不是问题)
我的问题是:如何强制 C++11 API wait_for() 与 MONOTONIC_CLOCK 一起使用?
实际上我想保留“CODE A”,但需要 MONOTONIC_CLOCK 的支持或设置。谢谢
// condition_variable::wait_for example
#include <iostream> // std::cout
#include <thread> // std::thread
#include <chrono> // std::chrono::seconds
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable, std::cv_status
std::condition_variable cv;
int value;
void read_value() {
std::cin >> value;
cv.notify_one();
}
int main ()
{
std::cout << "Please, enter an integer (I'll be printing …Run Code Online (Sandbox Code Playgroud) 假设某些条件变量"cond"与互斥变量"mutex"相关联.如果线程cond在调用后处于休眠状态pthread_cond_wait(&cond,&mutex),并且另一个已mutex锁定的线程已完成,则该线程在调用pthread_cond_signal(&cond)之前或之后调用pthread_mutex_unlock(&mutex)是否重要?它是否甚至需要解锁互斥锁pthread_cond_signal(&cond),因为睡眠线程无论如何都会获取互斥锁?
编辑:根据https://computing.llnl.gov/tutorials/pthreads/#ConVarOverview,"调用pthread_cond_signal()后未能解锁互斥锁可能不允许匹配的pthread_cond_wait()例程完成(它将保持阻塞状态). " 我想那时,解锁,也许只是之后才需要.
我正在使用Pthreads编写一个Web服务器(我吮吸它)(我甚至更多),我就陷入困境.服务器的模型是boss-worker,因此boss线程在程序开始时实例化所有工作线程.存在一个全局队列,用于存储传入连接的套接字.boss线程是在接受连接时将所有项(套接字)添加到队列的线程.然后,所有工作线程等待将项目添加到全局队列,以便它们接受处理.
只要连接服务器的次数少于服务器拥有的工作线程数,服务器就可以正常工作.因此,我认为我的互斥体出现问题(可能信号丢失了?)或线程在运行一次后被禁用(这可以解释为什么如果有8个线程,它只能解析第一个8个http请求).
这是我的全局队列变量.
int queue[QUEUE_SIZE];
Run Code Online (Sandbox Code Playgroud)
这是主线程.它创建一个队列结构(在其他地方定义),方法是enqueue,dequeue,empty等.当服务器接受连接时,它会将传入连接所在的套接字排入队列.在开始时调度的工作线程不断检查此队列以查看是否已添加任何作业,如果有作业,则它们将套接字出列,连接到该端口,并读取/解析/写入传入的http请求.
int main(int argc, char* argv[])
{
int hSocket, hServerSocket; /* handle to socket */
struct hostent* pHostInfo; /* holds info about a machine */
struct sockaddr_in Address; /* Internet socket address stuct */
int nAddressSize = sizeof(struct sockaddr_in);
int nHostPort;
int numThreads;
int i;
init(&head,&tail);
//**********************************************
//ALL OF THIS JUST SETS UP SERVER (ADDR STRUCT,PORT,HOST INFO, ETC)
if(argc < 3) {
printf("\nserver-usage port-num num-thread\n");
return 0;
}
else {
nHostPort=atoi(argv[1]);
numThreads=atoi(argv[2]);
}
printf("\nStarting server"); …Run Code Online (Sandbox Code Playgroud) 所以我发现,如果你没有在c ++ 11中持有锁,那么发出一个条件变量是合法的.这似乎打开了一些令人讨厌的竞争条件的大门:
std::mutex m_mutex;
std::condition_variable m_cv;
T1:
std::unique_lock<std::mutex> lock(m_mutex);
m_cv.wait(lock, []{ return !is_empty(); });
T2:
generate_data();
m_cv.notify();
Run Code Online (Sandbox Code Playgroud)
是否保证T1永远不会在我们首先检查is_empty()(它返回true)的情况下结束,然后被T2抢占,这会创建一些数据并在我们实际等待它之前发出条件变量的信号?
如果这可以保证工作(我猜是这样,否则它看起来像是一个故意错误的API设计),这实际上是如何实现linux和stdlibc++?似乎我们需要另一个锁以避免这种情况.
我有一个std::queue使用C ++ 11语义来允许并发访问的包装器。该std::queue保护带std::mutex。将项目推送到队列时,std::condition_variable会通过调用通知a notify_one。
有两种从队列中弹出项目的方法。一种方法将无限期地阻塞,直到使用将该项目推送到队列中为止std::condition_variable::wait()。第二个将阻塞std::chrono::duration单位使用的时间std::condition_variable::wait_for():
template <typename T> template <typename Rep, typename Period>
void ConcurrentQueue<T>::Pop(T &item, std::chrono::duration<Rep, Period> waitTime)
{
std::cv_status cvStatus = std::cv_status::no_timeout;
std::unique_lock<std::mutex> lock(m_queueMutex);
while (m_queue.empty() && (cvStatus == std::cv_status::no_timeout))
{
cvStatus = m_pushCondition.wait_for(lock, waitTime);
}
if (cvStatus == std::cv_status::no_timeout)
{
item = std::move(m_queue.front());
m_queue.pop();
}
}
Run Code Online (Sandbox Code Playgroud)
当我在空队列中像这样调用此方法时:
ConcurrentQueue<int> intQueue;
int value = 0;
std::chrono::seconds waitTime(12);
intQueue.Pop(value, waitTime);
Run Code Online (Sandbox Code Playgroud)
然后12秒后,对Pop()的调用将退出。但是,如果将waitTime设置为std::chrono::seconds::max(),则对Pop()的调用将立即退出。毫秒:: max()和小时数:: max()相同。但是,days …
我需要弄清楚lock和condition_variable是如何工作的.
在这里cminplusreference的-slightly modified-code中
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
// Wait until main() sends data
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return ready;});
// after the wait, we own the lock.
std::cout << "Worker thread is processing data\n";
data += " after processing";
// Send data back to main()
processed = true;
std::cout << "Worker thread signals data processing completed\n";
// Manual unlocking is done before notifying, to avoid waking …Run Code Online (Sandbox Code Playgroud) 我在某些环境中测试了这种情况,我得到了以下流程:
但是,从手册页(http://linux.die.net/man/3/pthread_cond_wait)或(http://linux.die.net/man/3/pthread_cond_signal),我找不到任何保证以下内容场景不可能发生:
哪个是执行信号的 2个线程可以在任何等待线程有机会运行之前运行.(调度可能性)
[现在,我知道如果这是用信号量完成的,那么第二种情况永远不会发生......但在我的情况下,我真的需要用cond-vars来做这件事!]
在我的情况下,每个帖子都会增加谓词,所以当等待的Thread2唤醒时,它将检查谓词(在这种情况下增加2),使线程不再睡眠,它会使谓词减1(意思是那个帖子被消耗了).
如果这种情况发生,则意味着"Thread1"可能不会在发生进一步发布之前唤醒,尽管谓词增加了两次(post)并且仅减少一次(Thread2 等待). 更糟糕的是,第三次等待可能永远不会阻塞,因为它将消耗先前挂起的谓词增量.
我还不能触发这个问题,但是有人知道这是否是一种可能的情况?
注意克服这种可能性,我已经取代了pthread_cond_signal()通过pthread_cond_broadcast()使双方Thread1和Thread2保证醒来,消耗2个增量.然而,这个解决方案会略微降低(甚至可能不会显着)性能,我敢打赌,对于那些为什么我们在这里使用广播的人来说这并不明显.
我不确定我是否真的理解为什么std::condition_variable需要额外std::mutex的参数?它不应该被自己锁定吗?
#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>
std::condition_variable cv;
std::mutex cv_m;
int i = 0;
bool done = false;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cout << "Waiting... \n";
cv.wait(lk, []{return i == 1;});
std::cout << "...finished waiting. i == 1\n";
done = true;
}
void signals()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Notifying falsely...\n";
cv.notify_one(); // waiting thread is notified with i == 0.
// cv.wait wakes up, checks i, and goes back to waiting
std::unique_lock<std::mutex> …Run Code Online (Sandbox Code Playgroud) 我查看了VC++的实现std::condition_variable(lock,pred),基本上,它看起来像这样:
template<class _Predicate>
void wait(unique_lock<mutex>& _Lck, _Predicate _Pred)
{ // wait for signal and test predicate
while (!_Pred())
wait(_Lck);
}
Run Code Online (Sandbox Code Playgroud)
基本上,裸wait调用_Cnd_waitX调用_Cnd_wait哪些调用do_wait哪些调用cond->_get_cv()->wait(cs);(所有这些都在文件cond.c中).
cond->_get_cv()回报Concurrency::details::stl_condition_variable_interface.
如果我们转到该文件primitives.h,我们会看到在Windows 7及更高版本下,我们有一个stl_condition_variable_win7包含旧的win32 CONDITION_VARIABLE和wait调用的类__crtSleepConditionVariableSRW.
进行一些汇编调试,__crtSleepConditionVariableSRW只需提取SleepConditionVariableSRW函数指针,然后调用它.
事情就是这样:据我所知,win32 CONDITION_VARIABLE不是内核对象,而是用户模式对象.因此,如果某个线程通知此变量并且没有线程实际上在其上休眠,则您丢失了通知,并且线程将保持休眠状态,直到超时或其他某个线程通知它.一个小程序实际上可以证明它 - 如果你错过了通知点 - 你的线程将保持睡眠,虽然其他一些线程通知它.
我的问题是这样的:
一个线程等待条件变量,谓词返回false.然后,发生上面解释的整个呼叫链.在那个时候,另一个线程改变了环境,因此谓词将返回true 并通知条件变量.我们在原始线程中传递了谓词,但我们仍然没有进入SleepConditionVariableSRW- 调用链很长.
所以,虽然我们通知了条件变量并且条件变量上的谓词肯定会返回true(因为通知程序是这样做的),我们仍然会阻塞条件变量,可能永远.
这是怎么表现的?这似乎是一个巨大的丑陋竞争条件等待发生.如果您通知条件变量并且它的谓词返回true - 则该线程应该解除阻塞.但是,如果我们在检查谓词和睡觉之间处于不确定状态 - 我们将永远被阻止.std::condition_variable::wait不是原子功能.
标准对此有何看法,是否真的是竞争条件?
根据http://en.cppreference.com/w/cpp/thread/condition_variable/wait:
以原子方式释放锁,阻止当前正在执行的线程,并将其添加到等待*this的线程列表中.执行notify_all()或notify_one()时,线程将被解除阻塞.它也可能是虚假的解锁.取消阻止时,无论原因如何,都会重新获取锁定并等待退出.如果此函数通过异常退出,则还会重新获取锁定.(直到C++ 14)
我无法理解为什么从C++ 14开始删除突出显示的语句.
这是不是意味着:
从C++ 14开始,如果此函数通过异常退出,则不会重新获取锁定?
如是:
背后的理由是什么?