小编val*_*ldo的帖子

零大小的结构

根据C++标准(继承自C),空结构仍然具有非零大小.这个(可怜的恕我直言)的原因是两个不同的变量应该有不同的地址.现在,继承一个空结构并不总是"膨胀"该对象.但在某些情况下情况就是这样.

我有一个相当复杂的类架构,涉及激烈的模板巫术.结果,最后的类(我需要创建的实例)可能有几个继承的空结构.由于这个事实,他们中的一部分最终可能会被夸大.最糟糕的是,他们的内存布局实际上取决于继承的顺序.

如果有可能的话,我想摆脱这一切.

是否有一个C++编译器可以配置为消除这种空间浪费,实际上是打破标准的代价?

编辑:

我是说这个:

struct Empty1 {};
struct Empty2 {};

struct NonEmpty {
    int Value;
};

struct MyClass1
    :public NonEmpty
    ,public Empty1
    ,public Empty2
{
};

struct MyClass2
    :public Empty1
    ,public NonEmpty
    ,public Empty2
{
};

struct MyClass3
    :public Empty1
    ,public Empty2
    ,public NonEmpty
{
};

STATIC_ASSERT(sizeof(MyClass1) == 8);
STATIC_ASSERT(sizeof(MyClass2) == 4);
STATIC_ASSERT(sizeof(MyClass3) == 8);
Run Code Online (Sandbox Code Playgroud)

不仅空结构会使对象膨胀(当多个这样的东西继承时),而且结果还取决于空结构的继承顺序.

c++

15
推荐指数
3
解决办法
3384
查看次数

Heap针对(但不限于)单线程使用进行了优化

我在我的一个项目中使用自定义堆实现.它由两个主要部分组成:

  1. 修复了大小块堆.即只分配特定大小的块的堆.它分配更大的内存块(虚拟内存页或来自另一个堆),然后将它们分成原子分配单元.

    它快速执行分配/释放(在O(1)中)并且没有内存使用开销,没有考虑外部堆强加的事情.

  2. 全球通用堆.它由上面(固定尺寸)堆的桶组成.WRT它选择适当存储桶的请求分配大小,并通过它执行分配.

    由于整个应用程序(大量)是多线程的 - 全局堆在其操作期间锁定适当的存储桶.

    注意:与传统堆相比,此堆不仅要求分配大小,还要求释放分配大小.这允许在没有搜索或额外的内存开销的情况下识别适当的桶(例如在分配的块之前保存块大小).虽然不太方便,但在我的情况下这是好的.此外,由于"桶配置"在编译时是已知的(通过C++模板voodoo实现) - 在编译时确定适当的桶.

到目前为止,一切看起来(并且有效).

最近我研究了一种能够大量执行堆操作的算法,并且自然会受到堆性能的影响.分析显示其锁定会对其性能产生很大影响.也就是说,堆本身工作得非常快(典型的分配只涉及一些内存解除引用指令),但由于整个应用程序是多线程的 - 适当的存储桶受关键部分的保护,它依赖于互锁指令,这些指令很多重.

我通过给这个算法提供了自己的专用堆来解决这个问题,这个堆不受关键部分的保护.但这在代码级别强加了几个问题/限制.例如,需要在堆栈深处传递上下文信息,无论堆可能在哪里.也可以使用TLS来避免这种情况,但这可能会导致我在特定情况下重新进入时出现一些问题.

这让我想知道:是否有一种已知的技术来优化堆(但不限于)单线程使用?

编辑:

特别感谢@Voo建议查看google的tcmalloc.

它似乎与我做的更多或更少(至少对于小对象)的工作类似.但此外,他们通过维护每线程缓存来解决我所遇到的确切问题.

我也想过这个方向,但我想保持每线程.然后释放从属于另一个线程的堆分配的内存块有点棘手:应该将其插入到一个锁定队列中,并且应该通知其他线程,并异步释放挂起的分配.异步释放可能会导致问题:如果该线程由于某种原因而忙(例如执行积极的计算) - 实际上不会发生内存释放.此外,在多线程场景中,释放的成本要高得多.

OTOH使用缓存的想法似乎更简单,更有效.我会尝试解决它.

非常感谢.

PS:

事实上谷歌的tcmalloc很棒.我相信它的实现与我所做的非常相似(至少是固定大小的部分).

但是,要迂腐,有一件事我的堆优越.根据文档,tcmalloc大约1%的开销(渐近),而我的开销是0.0061%.确切地说是4/64K.

:)

c c++ heap

15
推荐指数
1
解决办法
697
查看次数

DMA传输RAM到RAM

我的一个朋友告诉我,在x86架构上,DMA控制器无法在两个不同的RAM位置之间进行传输.它只能在RAM和外设之间传输(如PCI总线).

这是真的?

因为AFAIK DMA控制器应该能够位于BUS上并具有地址的任意设备之间.特别是如果源和destionation地址属于同一物理设备,我认为没有问题.

c windows x86 dma

14
推荐指数
2
解决办法
6150
查看次数

快速简单的图像哈希算法

我需要一个(最好是简单快速)的图像散列算法.散列值用于查找表,而不用于加密.

一些图像是"计算机图形" - 即纯色填充的光栅,光栅化文本等,而还有"摄影"图像 - 包含丰富的色谱,大多是光滑的,具有合理的噪声幅度.

我也希望哈希算法能够应用于特定的图像部分.我的意思是,图像可以分为网格单元格,每个单元格的哈希函数应该仅取决于该单元格的内容.因此,如果两个图像具有共同区域(如果它们被适当地对齐),则可以快速发现.

注意:我只需要知道两个图像(或它们的部分)是否相同.也就是说,我不需要匹配类似的图像,不需要特征识别,相关和其他DSP技术.

我想知道什么是首选的散列算法.

对于"摄影"图像,只需对网格单元格内的所有像素进行异或运算即可.不同图像的相同散列值的概率非常低,特别是因为(几乎白色)噪声的存在打破了所有潜在的对称性.此外,这种散列函数的频谱看起来很好(任何值都可能以几乎相同的概率).

但是这种天真的算法可能不会与"人工"图形一起使用.对于这样的图像,相同的像素,重复图案,几何偏移不变性是非常常见的.对于具有偶数个相同像素的任何图像,对所有像素进行异或将给出0.

使用像CRT-32这样的东西看起来很有希望,但我想更快地找出一些东西.我想到了迭代公式,每个新像素都会改变当前的哈希值,如下所示:

hashValue = (hashValue * /*something*/ | newPixelValue) % /* huge prime */
Run Code Online (Sandbox Code Playgroud)

做模数素数应该可以很好地分散,所以我倾向于这个选项.但我想知道是否有更好的变种.

提前致谢.

algorithm hash image

12
推荐指数
2
解决办法
2万
查看次数

H.264编码的NAL /切片分割

我正在研究一种需要通过UDP(一种视频通话)实时传输H.264编码视频的应用程序.

最近我们改用硬件编码器,它只支持有限数量的H.264配置文件.结果,每个编码视频帧现在由单个NALu组成.更确切地说,对于IDR(关键)帧,编码器为其他帧生成SSP,PSP和单个IDR切片 - 单个非IDR切片.

现在,我的目标是将切片NALu分成几个较小的切片,因为如果NALu无法完全组装,则会丢失数据包 - 它完全丢失了.至少我需要在空间上分割切片,即将宏块的范围放入不同的NALus中.如果可能的话 - 我还想提取高质量的图层,以便可以通过更多冗余数据包(FEC)保护基础层.

注意:我不是在谈论转码.它是关于重新打包/重新格式化,定位宏块定义数据块并以不同的方式放置它们.

我现在正在尝试使用H.264标准规范和一些开源解码器代码来解析相应的数据头:SPS,PPS和编码片.这项任务似乎有可能,虽然有点棘手,但有很多技术细节.

我的问题是:这是一个已知的问题吗?是否有一些API /库正是这样做的?

c++ video-streaming h.264

11
推荐指数
1
解决办法
1679
查看次数

内核模式下的线程本地存储?

Windows中的内核模式驱动程序是否存在线程局部存储(TLS)等效(确切地说是Win32)?

我试图实现的目标:

最终,在我的驱动程序的调度程序中,它可能会调用许多其他函数(可能存在深度调用).我想提供一些特定于正在处理的请求的上下文信息.也就是说,我有一些结构,指针应该在所有被调用的函数中都可见,而不是将它作为参数显式传递给每个函数.

使用static/global不是一个完美的选择(多线程,同步对象等).

如果那是用户模式代码 - 在这种情况下显然会使用TLS.但是AFAIK没有像TlsGetValue/ 这样的内核模式功能TlsSetValue.这是有道理的 - 要使这些功能工作,必须首先分配一个进程范围的TLS索引.OTOH驱动程序代码可以在任意线程上调用,不限于特定进程.

但是,我实际上并不需要持久的特定于线程的存储.我只需要一个特定于线程的存储来进行顶级函数调用.

我想我知道如何以一种黑客的方式"实施"TLS.我将始终使用预定义的索引(例如,index = 0),而不是分配TLS索引.在顶级函数中,我将保存存储的TLS值,并用所需的值覆盖它.完成后,将恢复保存的值.

幸运的是我知道如何在Win32中实现TLS.TIB每个线程都有一个结构(线程信息块).在每个线程中,可以使用FS:[18h]选择器访问它.在TIB包含(除其他外)通过TLS使用的阵列.其余的非常简单.

但是,我更愿意使用官方API来实现类似的功能.

  • 是否有官方的内核模式API来实现我的需求?
  • 有理由避免我打算做的事吗?我知道重新进入可能存在问题(即一些代码调用我,我覆盖TLS值,然后最终调用原始代码,这可能依赖于TLS).但在我的具体情况下,这是不可能的?
  • 有没有那么脏的方法来解决这个问题?

提前致谢.

PS One理论上可以使用SEH(也存储每线程信息).也就是说,包装顶级代码__try/__except,然后在需要上下文信息的地方 - 用一些参数引发可持续异常,在__except块中用上下文信息填充参数,然后恢复执行.这是一个100%有效的程序流程,不使用未记录的功能.但对我来说这似乎是一个丑陋的黑客,更不用说性能并发症了.

windows winapi kernel thread-local-storage

9
推荐指数
2
解决办法
2719
查看次数

巨大的C文件调试问题

我的项目中有一个源文件,它有超过65,536个代码行(确切地说是112,444).我正在使用"sqlite amalgamation",它出现在一个巨大的源文件中.

我正在使用MSVC 2005.问题在调试期间到来.一切都编译和链接确定.但是当我尝试使用调试器进入函数时 - 它显示的代码行不正确.

有趣的是,正确的行号和调试器显示的行号之间的差异正好是65536.这让我怀疑(几乎可以肯定)一些无符号的短溢出.

我也怀疑它不是MSVC本身的错误.也许这是调试信息格式的限制.也就是说,MSVC使用的调试信息格式将行号存储为2字节短路.

有没有什么可以做的(除了将大文件切成几个较小的文件)?

c c++ visual-studio

7
推荐指数
1
解决办法
1114
查看次数

如何使用WinDbg创建内核转储

我正在使用WinDbg调试Windows的内核模式设备驱动程序.是否有可能按需创建一个小型转储?

我的意思是,我的一个断点被击中,系统停止了.我想创建一个minidump(让我们说只有堆栈).这有WinDbg关键字吗?

提前致谢

minidump kernel windbg

7
推荐指数
1
解决办法
8261
查看次数

禁止在 LLVM 中评估“未定义的结果”

以下代码由clang编译到wasm平台:

uint64_t Get() const
{
    uint32_t ord = -m_Order;
    if (ord >= 64)
        return 0;

    return m_Num >> ord;
}
Run Code Online (Sandbox Code Playgroud)

编译后的 wasm 代码(启用优化)如下所示:

        i64.const 0

        local.get $l4
        i32.const 0
        local.get $p2
        i32.sub
        local.tee $l5
        i64.extend_i32_u
        i64.shr_u

        local.get $l5
        i32.const 63
        i32.gt_u
        select
Run Code Online (Sandbox Code Playgroud)

正如我们所看到的,表达式m_Num >> ord总是被求值,但最终结果将是 it 或0(第一个命令将其放在操作数堆栈上)。

我们在虚拟机上运行生成的 wasm 代码。问题是:当-m_Order大于63时,程序崩溃(即陷入困境,虚拟机不会崩溃),因为移位操作比操作数大小更多的位被认为是未定义的行为。

根据 LLVM 文档,这不是未定义的行为,它只是未定义的结果(所谓的毒害值)。

所以,我的问题是:是否有可能阻止 LLVM 进行这种优化?即不允许优化器产生未定义的结果,这些结果不应该由原始代码产生?

更新:

澄清:正如我们所发现的,WebAssembly 标准明确允许这样做。对于移位运算符,移位计数可以大于最大位数,在这种情况下,移位计数必须以最大位数为模进行处理(类似于 x86 处理器处理此问题的方式)。所以它甚至不是未定义的结果。

所以这是我们虚拟机的问题,它与标准有偏差。解决这个问题不是问题,但升级整个系统就有问题,所以我们更愿意保留当前的行为。我们需要一种解决该问题的方法。

我发现的一种解决方案是在块内调用一些第三方虚拟函数if,这将强制编译器生成正确的分支,而不是计算所有变体并通过select. 我的意思是:

uint64_t Get() const
{ …
Run Code Online (Sandbox Code Playgroud)

c c++ clang webassembly

7
推荐指数
0
解决办法
94
查看次数

意外的C/C++按位移位运算符结果

我想我会疯了.

我有一段代码需要创建一个(无符号)整数,其N后续位设置为1.确切地说,我有一个位掩码,在某些情况下,我想将它设置为一个实心的rnage.

我有以下功能:

void MaskAddRange(UINT& mask, UINT first, UINT count)
{
    mask |= ((1 << count) - 1) << first;
}
Run Code Online (Sandbox Code Playgroud)

简单来说:1 << count在二进制表示中100...000(零的数量是count),从这样的数字中减去1给出011...111,然后我们只是左移它first.

当满足以下明显限制时,上述结果应产生正确的结果:

first + count <= sizeof(UINT)*8 = 32

请注意,它也应该适用于"极端"情况.

  • 如果count = 0我们有(1 << count) = 1,因此((1 << count) - 1) = 0.
  • 如果count = 32我们有(1 << count) = 0,因为前导位溢出,并且根据C/C++规则,按位移位运算符不是循环的.然后 …

c bit-manipulation

6
推荐指数
1
解决办法
4820
查看次数