背景:
我问这个是因为我目前有一个包含许多(数百到数千)个线程的应用程序.这些线程中的大多数在很长一段时间内处于空闲状态,等待将工作项放入队列中.当工作项可用时,然后通过调用一些任意复杂的现有代码来处理它.在某些操作系统配置中,应用程序会遇到控制最大用户进程数的内核参数,因此我想尝试减少工作线程数的方法.
我建议的解决方案
它似乎是一个基于协程的方法,我用协程替换每个工作线程,将有助于实现这一目标.然后,我可以拥有一个由实际(内核)工作线程池支持的工作队列.当项目被放置在特定协程的队列中进行处理时,会将一个条目放入线程池的队列中.然后它将恢复相应的协同程序,处理其排队的数据,然后再次暂停它,释放工作线程以执行其他工作.
实施细节:
在考虑如何做到这一点时,我无法理解无堆栈和堆栈协程之间的功能差异.我有一些使用Boost.Coroutine库的堆栈协同程序的经验.我发现从概念层面理解它相对容易:对于每个协同程序,它维护CPU上下文和堆栈的副本,当你切换到协程时,它切换到保存的上下文(就像内核模式调度程序一样) ).
对我来说不太清楚的是无堆栈协程与此有何不同.在我的应用程序中,与上述工作项排队相关的开销量非常重要.我见过的大多数实现,比如新的CO2库,都表明无堆栈协程提供了更低开销的上下文切换.
因此,我想更清楚地理解无堆栈和堆栈协程之间的功能差异.具体来说,我想到了这些问题:
像这样的参考文献表明,区别在于你可以在一个堆栈与无堆栈协程中产生/恢复.是这样的吗?有一个简单的例子,我可以在一个堆栈的协程中做但不能在无堆栈的协同程序中吗?
使用自动存储变量(即"堆栈中的变量")是否有任何限制?
我可以从无堆协程中调用哪些函数有任何限制吗?
如果无堆栈协程没有保存堆栈上下文,那么当协同程序运行时,自动存储变量会去哪里?
我正在更新一个项目以使用C ++ 17,发现一些实例,遵循该模式的代码在最新版本的clang上导致了编译错误:
#include <boost/variant.hpp>
struct vis : public boost::static_visitor<void>
{
void operator()(int) const { }
};
int main()
{
boost::variant<int> v = 0;
boost::apply_visitor(vis{}, v);
}
Run Code Online (Sandbox Code Playgroud)
在C ++ 17模式下使用clang v8.0,此操作失败,并显示以下错误:
<source>:11:30: error: temporary of type 'boost::static_visitor<void>' has protected destructor
boost::apply_visitor(vis{}, v);
^
/opt/compiler-explorer/libs/boost_1_64_0/boost/variant/static_visitor.hpp:53:5: note: declared protected here
~static_visitor() = default;
Run Code Online (Sandbox Code Playgroud)
但是,它可以在C ++ 14模式下干净地编译。我发现如果将花括号初始化更改vis{}
为括号vis()
,则可以在两种模式下正确编译。我尝试过的每个gcc版本都允许在C ++ 17模式下使用这两种变体。
这是从C ++ 14到C ++ 17的正确行为更改,还是这是一个叮当响的错误?如果正确,为什么现在在C ++ 17中无效(或者也许一直如此,但是clang仅在较早的标准版本中允许使用)?
我正在编写一个简单的Python应用程序,它使用matplotlib在屏幕上显示一些数字.生成的数字数量基于用户输入和整个应用程序生命周期的变化.用户能够发出"绘图"命令以生成具有所选数据系列的新图形窗口.为了改善用户体验,我想提供另一个命令,它将以一种方便的方式以编程方式排列所有打开的图形窗口(例如,将它们平铺在可用的屏幕空间中).
我相信已经找到了允许我调整图窗口大小的API(以像素为单位),但是没有成功找到在屏幕上设置其绝对位置的方法.有没有办法在不深入了解正在使用的后端的细节的情况下做到这一点?我想以后端不可知的方式执行此操作,以便我可以避免依赖可能在将来更改的实现细节.
一位同事最近遇到了一个问题,归结为我们认为具有两个线程的C++应用程序中的以下事件序列:
线程A持有互斥锁.
当线程A持有互斥锁时,线程B会尝试锁定它.由于它被保持,线程B被暂停.
线程A完成它持有互斥锁的工作,从而释放互斥锁.
此后不久,线程A需要触摸受互斥锁保护的资源,因此它会再次锁定它.
似乎线程A再次被赋予互斥锁; 线程B仍在等待,即使它首先"询问"锁定.
这个事件序列是否适合C++ 11 std::mutex
和/或pthreads 的语义?老实说我以前从未想过互斥体的这个方面.
我有一个C++ 03应用程序,其中std::vector<T>
类型作为临时缓冲区使用.因此,它们通常会使用std::vector<T>::resize()
以确保它们足够大以在使用前保存所需数据.这个函数的C++ 03原型实际上是:
void resize(size_type n, value_type val = value_type());
Run Code Online (Sandbox Code Playgroud)
因此,实际上在调用时resize()
,通过添加适当数量的副本来放大矢量val
.但是,通常我只需要知道它vector
足够大以容纳我需要的数据; 我不需要用任何值初始化它.复制构造新值只是浪费时间.
C++ 11拯救了(我想):在它的规范中,它分为resize()
两个重载:
void resize(size_type n); // value initialization
void resize(size_type n, const value_type &val); // initialization via copy
Run Code Online (Sandbox Code Playgroud)
这非常适合C++的理念:只需支付你想要的东西.正如我所指出的那样,我的应用程序不能使用C++ 11,所以当我遇到Boost.Container库时,我很高兴,它表明在其文档中支持这个功能.具体来说,boost::container::vector<T>
实际上有三个重载resize()
:
void resize(size_type n); // value initialization
void resize(size_type n, default_init_t); // default initialization
void resize(size_type n, const value_type &val); // initialization via copy
Run Code Online (Sandbox Code Playgroud)
为了验证我理解了所有内容,我进行了快速测试以验证C++ 11的行为std::vector<T>
和boost::container::vector<T> …
我有一个服务器应用程序,在dbus上创建一个总线,运行几分钟后,我得到了一个我从未见过的错误.你有什么想法吗?
*** longjmp causes uninitialized stack frame ***: /home/user/Workspace/DBus_Server/Debug/DBus_Server terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x37)[0x7f8d8911c7f7]
/lib/x86_64-linux-gnu/libc.so.6(+0xf8789)[0x7f8d8911c789]
/lib/x86_64-linux-gnu/libc.so.6(__longjmp_chk+0x33)[0x7f8d8911c6f3]
/usr/lib/x86_64-linux-gnu/libcurl-nss.so.4(+0xd795)[0x7f8d88272795]
/lib/x86_64-linux-gnu/libc.so.6(+0x36420)[0x7f8d8905a420]
/lib/x86_64-linux-gnu/libc.so.6(__poll+0x53)[0x7f8d890f9773]
/usr/lib/libdbus-c++-1.so.0(_ZN4DBus15DefaultMainLoop8dispatchEv+0x161)[0x7f8d89b6b481]
/usr/lib/libdbus-c++-1.so.0(_ZN4DBus13BusDispatcher5enterEv+0x63)[0x7f8d89b6c293]
/home/user/Workspace/DBus_Server/Debug/DBus_Server[0x401333]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f8d8904530d]
/home/user/Workspace/DBus_Server/Debug/DBus_Server[0x4011c9]
Run Code Online (Sandbox Code Playgroud) 当我需要扫描一堆字符串中的值时,我经常发现自己sscanf()
严格地回到C语言,因为它简单易用.例如,我可以非常简洁地从字符串中拉出几个double值:
string str;
double val1, val2;
if (sscanf(str.c_str(), "(%lf,%lf)", &val1, &val2) == 2)
{
// got them!
}
Run Code Online (Sandbox Code Playgroud)
这显然不是很C++.我不一定认为这是一种憎恶,但我总是在寻找一种更好的方法来完成一项共同的任务.我理解读取字符串的"C++方式"是istringstream
,但是处理上面的格式字符串中的括号和逗号所需的额外输入只会使得我想要使用它太麻烦.
是否有一种很好的方法可以以类似于上面的方式将内置设施弯曲到我的意愿,或者是否有一个好的C++库以更加类型安全的方式完成上述操作?看起来Boost.Format确实以一种很好的方式解决了输出问题,但我没有发现任何类似的输入简洁.
我有一个C++对象文件,其中包含一些C++模板函数的实例.有问题的目标文件为模板参数的几种不同组合实例化相同的功能.我正在尝试调试一个问题,并希望查看模板函数的特定实例化的反汇编(也就是说,我知道我想要检查的函数的模板参数).我通常会这样做objdump
来反汇编目标文件,但它(至少在默认情况下)不能解析C++函数名称.有没有办法做到这一点?目标文件是使用gcc 4.6.1创建的.
我有一个项目,其中包含一堆遵循标准C++头命名约定的C++头文件; 也就是说,一个名为Foo的类将在一个名为Foo
,不是Foo.h
或的文件中声明Foo.hh
.是否有一种很好的方法来配置vim只为这些文件进行语法高亮?稍微不那么令人满意的后备是为所有没有扩展名的文件启用C++风格的突出显示.我不确定是否有更复杂的方法来检测文件类型而不是仅仅依赖于它的扩展.
我有一些模板密集的C++代码,我想确保编译器尽可能地优化,因为它在编译时有大量的信息.为了评估它的性能,我决定看一下它生成的目标文件的反汇编.以下是我从中得到的片段objdump -dC
:
0000000000000000 <bar<foo, 0u>::get(bool)>:
0: 41 57 push %r15
2: 49 89 f7 mov %rsi,%r15
5: 41 56 push %r14
7: 41 55 push %r13
9: 41 54 push %r12
b: 55 push %rbp
c: 53 push %rbx
d: 48 81 ec 68 02 00 00 sub $0x268,%rsp
14: 48 89 7c 24 10 mov %rdi,0x10(%rsp)
19: 48 89 f7 mov %rsi,%rdi
1c: 89 54 24 1c mov %edx,0x1c(%rsp)
20: e8 00 00 00 00 callq 25 …
Run Code Online (Sandbox Code Playgroud)