用cgo

时间:2016-06-24 22:30:58

标签: go cgo

所以,我试图在没有忙碌等待的情况下从stdin读取,忽略EOF,因为我的情况下的客户端会来来去去。在C中我会使用一个简单的select()或poll(),但我正在尝试学习Go,而我对于缺少select()或poll()感到非常沮丧。我在Go中找不到使用select和channel的好方法,因为Read()将立即返回EOF并且我回到忙碌的等待状态。 syscall.Select()似乎是最好的方法,但Go并没有费心去实现FD_SET! 叹息

所以,我正在尝试使用cgo。

package main

/*
#include <stdlib.h>
#include <sys/select.h>
void _FD_SET(int sysfd, void *set) {
    FD_SET(sysfd, (fd_set*)set);
}
*/
import "C"

import (
    "unsafe"

但是当我尝试在我的Mac上构建它时,我得到了这个。

# github.com/msoulier/mlogd
could not determine kind of name for C._FD_SET

clang errors for preamble:
src/github.com/msoulier/mlogd/mlogd.go:6:14: error: expected identifier or '('
void _FD_SET(int sysfd, void *set) {
             ^
src/github.com/msoulier/mlogd/mlogd.go:6:14: error: expected ')'
src/github.com/msoulier/mlogd/mlogd.go:6:13: note: to match this '('
void _FD_SET(int sysfd, void *set) {
            ^
2 errors generated.

如果我将导入合并在一起,那么大多数错误就会消失。

package main

/*
#include <stdlib.h>
#include <sys/select.h>
void _FD_SET(int sysfd, void *set) {
    FD_SET(sysfd, (fd_set*)set);
}
*/
import (
    "C"
    "unsafe"
    "syscall"

但还有一个。

# github.com/msoulier/mlogd
could not determine kind of name for C._FD_SET

所以,我在这里寻找两件事。

  1. 为什么我在这里做错了cgo?从我所读到的,这应该“正常工作”。
  2. 有没有更好的方法从stdin中无限期地阅读,没有忙碌的等待,而忽略了EOF?
  3. 我的环境。

    msoulier@merlin:~/work/go$ go version
    go version go1.6.2 darwin/amd64
    msoulier@merlin:~/work/go$ go env
    GOARCH="amd64"
    GOBIN=""
    GOEXE=""
    GOHOSTARCH="amd64"
    GOHOSTOS="darwin"
    GOOS="darwin"
    GOPATH="/Users/msoulier/work/go"
    GORACE=""
    GOROOT="/usr/local/Cellar/go/1.6.2/libexec"
    GOTOOLDIR="/usr/local/Cellar/go/1.6.2/libexec/pkg/tool/darwin_amd64"
    GO15VENDOREXPERIMENT="1"
    CC="clang"
    GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common"
    CXX="clang++"
    CGO_ENABLED="1"
    

    提前致谢。必须比这更简单。

    我选择了这一点。

    // loop forever - we expect to be killed with a SIGTERM or SIGINT
    for {
        logger.Debug("going into select on stdin")
        var r_fdset syscall.FdSet
        for i := 0; i < 16; i++ {
            r_fdset.Bits[i] = 0
        }
        r_fdset.Bits[0] = 1
        selerr := syscall.Select(1, &r_fdset, nil, nil, nil)
        if selerr != nil {
            logger.Warning(selerr)
        }
    

    但即使输入用完,它也会立即返回。

    麦克

1 个答案:

答案 0 :(得分:1)

在Go中,您可以执行阻止操作。无处不在。

你把那些阻塞操作放在goroutine中,就像绿色线程/光纤一样。它们由Go运行时调度,可能位于实际线程上,也可能是共享线程。

然后你使用频道与你Go计划的其他部分交谈。

对于你的问题,在EOF之后,stdin总是可读的,只是停止阅读它。我的读者goroutine就在下面退出。

在这里,有一个我刚才写的样本:

package main

import (
    "fmt"
    "io"
    "os"
    "time"
)

func main() {
    var err error
    ch1 := make(chan []byte)
    ch2 := make(chan int)
    var buf []byte
    var i int
    var ok bool

    go reader(ch1)
    go counter(ch2)

    for {
        select {
        case buf, ok = <-ch1:
            if ok {
                _, err = os.Stdout.Write([]byte("input: "))
                _, err = os.Stdout.Write(buf)
            }

        case i, ok = <-ch2:
            if ok {
                _, err = fmt.Println("count", i)
            }
        }
        if err != nil {
            fmt.Println("error", err)
        }
        if !ok {
            break
        }
    }
}

func counter(ch chan<- int) {
    i := 0
    for i < 5 {
        i++
        ch <- i
        time.Sleep(time.Second)
    }
    close(ch)
}

func reader(ch chan<- []byte) {
    var r int
    var err error
    for {
        buf := make([]byte, 4000)
        r, err = os.Stdin.Read(buf)
        if r > 0 {
            ch <- buf[:r]
        }
        if err != nil {
            fmt.Println("read error", err)
            if err == io.EOF {
                break
            }
            // Or really just about any error on read is fatal
            break
        }
    }
    close(ch)
}