5

WiringPi 'C' 库中有一个函数delay,类型为

void delay(unsigned int howLong);

此函数将代码的执行延迟howLong几毫秒。我在 haskell 中编写了绑定代码,以便能够调用此函数。haskell代码如下,

foreign import ccall "wiringPi.h delay" c_delay :: CUInt -> IO ()
hdelay :: Int -> IO ()
hdelay howlong = c_delay (fromIntegral howlong)

之后,我写了一个简单的haskell程序来调用这个函数。简单的haskell代码如下..

--导入相关库后我做了

main = wiringPiSetup
    >> delay 5000

但是延迟不会发生,或者说 ghc 编译器生成的可执行文件会立即退出。

有人能告诉我这里可能出什么问题吗?朝正确的方向轻推会有所帮助。

欢呼和问候。

4

1 回答 1

2

请忽略块引用中的部分,并查看下面的更新 - 由于与之相关的评论,我保留了原始的非解决方案。

您应该将其标记为importunsafe因为您希望主线程在函数执行时阻塞(请参阅@carl 下面的评论)。默认情况下,导入是安全的,而不是unsafe. 因此,将函数签名更改为此应该使主线程阻塞:

foreign import ccall unsafe "wiring.h delay" c_delay :: CUInt -> IO ()

此外,如果您计划编写多线程代码,多线程 FFI的 GHC 文档非常有用。似乎也是一个不错的开端。

更新

该行为似乎是由于信号中断处理(如果我没记错的话,这是在 GHC 7.4+ 中添加以修复一些错误)。更多细节在这里: http ://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Signals

请注意上面页面上的评论:Signal handling differs between the threaded version of the runtime and the non-threaded version

方法 1 -在 FFI 代码中处理信号中断:下面是一个玩具代码,它处理睡眠中的中断。我使用 ghc 7.6.1 在 Linux 2.6.18 上对其进行了测试。

C代码:

/** ctest.c **/
#include <unistd.h>
#include <stdio.h>
#include <time.h>

unsigned delay(unsigned sec)
{
  struct timespec req={0};
  req.tv_sec = sec;
  req.tv_nsec = 0;

  while (nanosleep(&req, &req) == -1) {
    printf("Got interrupt, continuing\n");
    continue;
    }
  return 1;
}

哈斯克尔代码:

{-# LANGUAGE ForeignFunctionInterface #-}
-- Filename Test.hs
module Main (main) where
import Foreign.C.Types

foreign import ccall safe "delay" delay :: CUInt -> IO CUInt

main =  do
    putStrLn "Sleeping"
    n <- delay 2000
    putStrLn $ "Got return code from sleep: " ++ show n

现在,在使用 ghc 7.6.1 (command: ghc Test.hs ctest.c) 编译后,它会一直等到 sleep 完成,并在每次在 sleep 期间收到中断信号时打印一条消息:

./Test
Sleeping
Got interrupt, continuing
Got interrupt, continuing
Got interrupt, continuing
Got interrupt, continuing
....
....
Got return code from sleep: 1

方法 2 -在调用 FFI 代码之前禁用 SIGVTALRM,然后重新启用:

我不确定禁用 SIGVTALRM 有什么影响。如果您无法更改 FFI 代码,这是在 FFI 调用期间禁用 SIGVTALRM 的替代方法。因此,FFI 代码在睡眠期间不会被中断(假设是 SIGVTALRM 导致了中断)。

{-# LANGUAGE ForeignFunctionInterface #-}
-- Test.hs
module Main (main) where
import Foreign.C.Types
import System.Posix.Signals

foreign import ccall safe "delay" delay :: CUInt -> IO CUInt

main =  do
    putStrLn "Sleeping"
    -- Block SIGVTALRM temporarily to avoid interrupts while sleeping
    blockSignals $ addSignal sigVTALRM emptySignalSet
    n <- delay 2
    putStrLn $ "Got return code from sleep: " ++ show n
    -- Unblock SIGVTALRM
    unblockSignals $ addSignal sigVTALRM emptySignalSet
    return ()
于 2013-03-05T15:24:53.923 回答