小编Mon*_*nad的帖子

多数据构造函数的Monad实例

我不久前开始使用Haskell,现在正在教我自己的monad,所以我在这里为自己想出了一个愚蠢的例子来帮助我理解monad的一个方面.

给定Certainty定义为的类型

data Certainty a = Definitely a | Perhaps a | Nope
Run Code Online (Sandbox Code Playgroud)

Monad所述类型的实例

instance Monad Certainty where
  return = ...
Run Code Online (Sandbox Code Playgroud)

如何return为Certainty及其每个数据构造函数定义该方法?

monads haskell

3
推荐指数
1
解决办法
126
查看次数

Haskell/Frege会不会重新计算惰性列表的元素?

假设我有一个所有素数的列表,定义为

primes :: (Enum ?, Integral ?) => [?]
primes = sieve [2..]
  where sieve :: (Integral ?) => [?] -> [?]
        sieve []     = undefined
        sieve (x:xs) = x : (sieve $ filter ((/= 0) . (flip mod x)) xs)
Run Code Online (Sandbox Code Playgroud)

我想primes通过多种不同的功能提供信息,例如:

sumOfPrimesLessThan :: (Integral ?) => ? -> ?
sumOfPrimesLessThan n = sum $ takeWhile (< n) primes
Run Code Online (Sandbox Code Playgroud)

要么

productOfPrimesLessThan :: (Integral ?) => ? -> ?
productOfPrimesLessThan n = foldl (*) 1 $ takeWhile (< n) …
Run Code Online (Sandbox Code Playgroud)

caching haskell lazy-evaluation frege

3
推荐指数
1
解决办法
187
查看次数

C/C++在引擎盖下按值返回struct

(这个问题特定于我的机器的架构和调用约定,Windows x86_64)

我不记得我在哪里读过这个,或者我是否正确地回忆过它,但我听说过,当一个函数应该按值返回一些结构或对象时,它会填充它rax(如果对象可以适合在寄存器宽度为64位)或传递一个指针,指向结果对象将在哪里(我猜测在调用函数的堆栈帧中分配)rcx,在那里它将执行所有通常的初始化,然后a mov rax, rcx为返回行程.就是这样的

extern some_struct create_it(); // implemented in assembly
Run Code Online (Sandbox Code Playgroud)

真的会有一个秘密的参数

extern some_struct create_it(some_struct* secret_param_pointing_to_where_i_will_be);
Run Code Online (Sandbox Code Playgroud)


我的记忆是正确的,还是我错了?如何通过函数的值返回大对象(即宽度超过寄存器宽度)?

c c++ assembly win64 x86-64

3
推荐指数
2
解决办法
881
查看次数

从设计的子例程返回到修改后的返回地址时,BR/RET 时序差异

在尝试 64 位 ARM 架构的过程中,我注意到根据是否使用brret用于从子例程返回而产生的特殊速度差异。

; Contrived for learning/experimenting purposes only, without any practical use
foo:
    cmp     w0, #0
    b.eq    .L0
    sub     w0, w0, #1
    sub     x30, x30, #4
    ret
.L0:
    ret ; Intentionally duplicated 'ret'
Run Code Online (Sandbox Code Playgroud)

该子例程的目的是通过返回到第一个调用的指令(即紧邻指向的指令之前的指令)来使调用者foo“重新输入”一次。通过一些粗略的计时,并且具有足够高的值,平均需要大约 1362 毫秒。奇怪的是,将第一个替换为使其运行速度提高了一倍,平均只需要 550 毫秒左右。foo w0foofoox30w0retbr x30

如果测试简化为仅使用裸ret/重复调用子例程,则时间差异就会消失br x30。是什么使得上面设计的带有 a 的子程序变慢ret

我在某种 ARMv8.2 (Cortex-A76 + Cortex-A55) 处理器上对此进行了测试。我不确定 big.LITTLE 会在多大程度上扰乱时间,但它们在多次运行中似乎非常一致。这绝不是一个真正的[微]基准,而是一个“如果运行N次大约需要多长时间”的事情。

assembly arm branch-prediction arm64

3
推荐指数
1
解决办法
311
查看次数

在 ARM 上同步 JIT/自修改代码的缓存

据我了解,编写并随后执行 JIT 或自修改代码的一般、更抽象的过程如下所示。

  • 编写生成的代码,
  • 确保它已刷新且全局可见0
  • 然后确保从中获取的指令将是所写入的指令。

这篇关于 x86 上自修改代码的文章中我可以看出,手动缓存管理显然是没有必要的。我认为 aclflushopt是必要的,但 x86 1显然会在从具有新指令的位置加载时自动处理缓存失效,这样指令提取就永远不会过时。我的问题不是关于 x86,但我想将其包括在内以进行比较。

AArch64 中的情况稍微复杂一些,因为它区分了可共享域以及缓存操作的“可见性”程度。仅从 ARMv8/ARMv9 的官方文档中,我首先得出了这个猜测。

  • 编写生成的代码,
  • dsb ishst确保在继续之前已全部写入,
  • 然后isb sy确保从内存中提取后续指令。

DMB/DSB/ISB 的文档说“ISB 后面的指令是从缓存或内存中获取的”。这给我的印象是缓存控制操作确实是必要的。我的新猜测是这样的。

  • 编写生成的代码,
  • dsb ishst确保在继续之前已全部写入,
  • 然后是ic ivau新代码占用的所有缓存行。

但我又忍不住觉得这也不太对劲。过了一会儿,我在文档中发现了一些我错过的东西,并且在一篇论文中发现了几乎相同的东西。他们都给出了一个看起来像这样的例子。

dc cvau, Xn ; Clean cache to PoU, so the newly written code will be visible
dsb ish     ; Wait for cleaning to finish
ic ivau, Xn ; Invalidate …
Run Code Online (Sandbox Code Playgroud)

assembly self-modifying memory-barriers cpu-cache arm64

3
推荐指数
1
解决办法
1198
查看次数

实现异步延迟

实现类似以下内容的明智方法是什么?

\n
// Plain C function for example purposes.\nvoid sleep_async(delay_t delay, void (* callback)(void *), void * data);\n
Run Code Online (Sandbox Code Playgroud)\n

即延迟后异步执行回调的一种手段。例如,POSIX 有一些函数可以执行类似的操作,但它们主要用于异步 I/O(请参阅了解我的意思)。根据该手册页,我对这些函数感兴趣的是它们如何“好像”在新线程上执行,其中实现可以选择生成“单个线程......以接收所有通知”。我知道有些人可能仍然选择为每个线程生成一个完整的线程,并且像这样的东西可能需要操作系统本身的支持,所以这只是一个例子。

\n

我已经有几种方法可以实现这一点(例如,按定时器循环上的唤醒时间排序的事件优先级队列,根本不需要启动线程),但我想知道是否已经存在 smart[er] 或[更多]我想要完成的事情的完整实现。例如,也许Task.Delay()C\xe2\x99\xaf 的实现(以及其他语言环境中的协程)在最小化线程生成量以获得异步延迟方面做了一些聪明的事情。

\n

我为什么要寻找这样的东西?正如标题所暗示的,我正在寻找异步的东西。上面的签名只是一个简单的 C 示例,大致说明了 POSIX 的作用。我正在实现一些 C++20 协程,供与朋友一起使用co_await,以及线程池等。安排任何最终会同步等待某事的事情可能是一个坏主意,因为它会阻止其他空闲线程执行任何工作。生成[并可能立即分离]一个新线程只是为了添加异步延迟似乎也不是一个非常聪明的想法。我的计时器循环想法可能没问题,但这意味着需要预定义的计时器粒度以及优先级队列的开销。

\n

编辑

\n

正如评论者提到的那样,我忽略了任何真正的目标平台集。我不希望针对“常用”桌面平台之外的任何东西,因此嵌入式开发的怪癖被忽略。我计划以这种方式使用异步延迟本身的方式不一定需要线程支持(一切都可以只在计时器循环上),但仍然需要并一致使用线程(即调度协程的线程池)。

\n

c c++ async-await

2
推荐指数
1
解决办法
831
查看次数

释放内存不会导致页面错误

与保留和提交虚拟存储器至过程实验,我分配64K字节的内存VirtualAlloc,memcpy"DA测试字符串进去,printf倒是它像一个字符串,释放的内存VirtualFree与所述MEM_RELEASE标志,并且printf"再次ð它.由于某种原因,不会触发页面错误.为什么是这样?

#include <stdio.h>
#include <windows.h>

INT main(DWORD argc, LPSTR argv[]) {
    SYSTEM_INFO info;
    DWORD dwPageSize;
    DWORD dwMemSize;
    LPVOID lpvMem;

    GetSystemInfo(&info);
    dwPageSize = info.dwPageSize;
    dwMemSize = 16 * dwPageSize;

    lpvMem = VirtualAlloc((LPVOID) 0x00F00000, dwMemSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!lpvMem) {
        printf("Error allocating virtual memory\n");
        return 1;
    }

    printf("lpvMem = 0x%08X\n", (UINT32) (UINT64) lpvMem);

    if (!memcpy(lpvMem, "I love foxes \\(^o^)/", 21)) {
        printf("Error copying memory (error code 0x%08X)\n", GetLastError()); …
Run Code Online (Sandbox Code Playgroud)

c windows winapi virtual-memory

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