从另一个线程发出信号的最快方法
Fastest way to signal one thread from another
我的代码看起来与下面非常相似。该代码有效,但我很好奇是否有更快(更低的延迟)从一个线程向另一个线程发送信号。
// condition_variable::wait (with predicate)
#include <iostream> // std::cout
#include <thread> // std::thread, std::this_thread::yield
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
int cargo = 0;
bool shipment_available()
{
return cargo!=0;
}
void consume ()
{
while(1)
{
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck,shipment_available);
// consume:
std::cout << cargo << '\n';
cargo=0;
}
}
int main ()
{
std::thread consumer_thread (consume);
// produce 10 items when needed:
int i=0;
while(1)
{
while (shipment_available()) std::this_thread::yield();
std::unique_lock<std::mutex> lck(mtx);
cargo = i++;
cv.notify_one();
if(i > 100)
break;
}
consumer_thread.join();
return 0;
}
你的例子中有很多错误,所以我会先尝试回答一些你应该在这个之前问过的问题。
关于你的例子
首先 - 这个例子没有意义 - 它实际上是同步的:两个线程不会同时 运行 - 其中一个总是等待另一个。如果在这种情况下 - 性能是您的主要目标 - 您应该将这段代码放在单线程中。
如果您希望使用所有 CPU 内核来提高性能 - 您需要使用完全不同的异步方法。您必须使用工作线程的线程池并在队列中向它们提供任务。这意味着,您必须更改代码的 架构 ,因此 - 它超出了您的问题范围。
然后,您的工作线程将不会通过从另一个线程简单地调用 thread::join
来结束。 thread::join
阻塞调用它的线程,直到目标线程退出。因此您的应用程序将在 join
调用点挂起,因为您的工作线程永远不会退出 while(1)
循环。你需要以某种方式告诉它,将不再有工作,它必须完成。您可以使用特殊的货物价值(例如负值)或停止标志,我在下面的示例中使用过。 std::thread
的文档:http://en.cppreference.com/w/cpp/thread/thread
另外,如果你用互斥来保护一些变量(并且你必须这样做,如果对它们的访问不是原子的并且它们同时在多个线程中使用),你应该不要在没有获得上述互斥锁的情况下使用它们——它总是会导致您出现某种同步错误。我在 std::unique_lock
范围之外的主线程中谈论 while (shipment_available())
。有了这个 - 代码可以正常编译并且可以正常工作,但是有一天,工作线程将写入 cargo
而主线程正在读取它的值,并且如果访问 int
在您的平台上不是原子的- 可能会发生意想不到且完全不可预测的事情。也许会导致应用程序崩溃,也许会导致读取错误的值。在这个特定的例子中——我无法想象会出现什么问题(但是 Mark Lakata 在评论中指出了一种情况),但在一般情况下——这是一个可怕的错误,这是令人难以置信的难以捕捉。有一个关于 C++11 线程和同步的很好的教程,它解释了这种类型的一些陷阱:http://baptiste-wicht.com/categories/c11-concurrency-tutorial.html
关于您的问题:
要提高示例的性能,您可以对 std::atomic
个对象使用无锁方法。 std::atomic
的文档:http://en.cppreference.com/w/cpp/atomic/atomic
应该说,采用这种方法——线程根本不休眠,将完全占据你的两个核心CPU。 yield
使其在资源管理方面稍微好一些,但会增加线程通信的延迟,因此可以将其删除。
密码
#include <iostream>
#include <thread>
#include <atomic>
// make your cargo an atomic object
// it does not need a mutex to sync access to it from several threads
std::atomic<int> cargo = 0;
// you should have some method to stop thread, it wont stop by itself by calling std::thread::join()
// the most simple one - is atomic stop flag.
std::atomic<bool> consumerThreadStopFlag = false;
bool shipment_available()
{
return cargo!=0;
}
void consume()
{
while(!consumerThreadStopFlag) // while stop flag is not set
{
while(!shipment_available())
std::this_thread::yield();
std::cout << cargo << '\n';
cargo=0;
}
}
int main ()
{
std::thread consumer_thread (consume);
// produce 10 items when needed:
int i=0;
while(1)
{
while (shipment_available())
std::this_thread::yield();
cargo = i++;
if(i > 100)
break;
}
consumerThreadStopFlag = true; // setup stop flag
consumer_thread.join(); // wait till thread leaves its while loop
return 0;
}
我的代码看起来与下面非常相似。该代码有效,但我很好奇是否有更快(更低的延迟)从一个线程向另一个线程发送信号。
// condition_variable::wait (with predicate)
#include <iostream> // std::cout
#include <thread> // std::thread, std::this_thread::yield
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
int cargo = 0;
bool shipment_available()
{
return cargo!=0;
}
void consume ()
{
while(1)
{
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck,shipment_available);
// consume:
std::cout << cargo << '\n';
cargo=0;
}
}
int main ()
{
std::thread consumer_thread (consume);
// produce 10 items when needed:
int i=0;
while(1)
{
while (shipment_available()) std::this_thread::yield();
std::unique_lock<std::mutex> lck(mtx);
cargo = i++;
cv.notify_one();
if(i > 100)
break;
}
consumer_thread.join();
return 0;
}
你的例子中有很多错误,所以我会先尝试回答一些你应该在这个之前问过的问题。
关于你的例子
首先 - 这个例子没有意义 - 它实际上是同步的:两个线程不会同时 运行 - 其中一个总是等待另一个。如果在这种情况下 - 性能是您的主要目标 - 您应该将这段代码放在单线程中。
如果您希望使用所有 CPU 内核来提高性能 - 您需要使用完全不同的异步方法。您必须使用工作线程的线程池并在队列中向它们提供任务。这意味着,您必须更改代码的 架构 ,因此 - 它超出了您的问题范围。
然后,您的工作线程将不会通过从另一个线程简单地调用 thread::join
来结束。 thread::join
阻塞调用它的线程,直到目标线程退出。因此您的应用程序将在 join
调用点挂起,因为您的工作线程永远不会退出 while(1)
循环。你需要以某种方式告诉它,将不再有工作,它必须完成。您可以使用特殊的货物价值(例如负值)或停止标志,我在下面的示例中使用过。 std::thread
的文档:http://en.cppreference.com/w/cpp/thread/thread
另外,如果你用互斥来保护一些变量(并且你必须这样做,如果对它们的访问不是原子的并且它们同时在多个线程中使用),你应该不要在没有获得上述互斥锁的情况下使用它们——它总是会导致您出现某种同步错误。我在 std::unique_lock
范围之外的主线程中谈论 while (shipment_available())
。有了这个 - 代码可以正常编译并且可以正常工作,但是有一天,工作线程将写入 cargo
而主线程正在读取它的值,并且如果访问 int
在您的平台上不是原子的- 可能会发生意想不到且完全不可预测的事情。也许会导致应用程序崩溃,也许会导致读取错误的值。在这个特定的例子中——我无法想象会出现什么问题(但是 Mark Lakata 在评论中指出了一种情况),但在一般情况下——这是一个可怕的错误,这是令人难以置信的难以捕捉。有一个关于 C++11 线程和同步的很好的教程,它解释了这种类型的一些陷阱:http://baptiste-wicht.com/categories/c11-concurrency-tutorial.html
关于您的问题:
要提高示例的性能,您可以对 std::atomic
个对象使用无锁方法。 std::atomic
的文档:http://en.cppreference.com/w/cpp/atomic/atomic
应该说,采用这种方法——线程根本不休眠,将完全占据你的两个核心CPU。 yield
使其在资源管理方面稍微好一些,但会增加线程通信的延迟,因此可以将其删除。
密码
#include <iostream>
#include <thread>
#include <atomic>
// make your cargo an atomic object
// it does not need a mutex to sync access to it from several threads
std::atomic<int> cargo = 0;
// you should have some method to stop thread, it wont stop by itself by calling std::thread::join()
// the most simple one - is atomic stop flag.
std::atomic<bool> consumerThreadStopFlag = false;
bool shipment_available()
{
return cargo!=0;
}
void consume()
{
while(!consumerThreadStopFlag) // while stop flag is not set
{
while(!shipment_available())
std::this_thread::yield();
std::cout << cargo << '\n';
cargo=0;
}
}
int main ()
{
std::thread consumer_thread (consume);
// produce 10 items when needed:
int i=0;
while(1)
{
while (shipment_available())
std::this_thread::yield();
cargo = i++;
if(i > 100)
break;
}
consumerThreadStopFlag = true; // setup stop flag
consumer_thread.join(); // wait till thread leaves its while loop
return 0;
}