xenomai xddp with std::thread



我需要在Xenomai机器上执行RT到NRT通信。

我实际上能够编译和运行这里提出的示例但是,如果尝试将pthreads替换为 std::thread ,如下所示:

#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <malloc.h>
#include <pthread.h>
#include <fcntl.h>
#include <errno.h>
#include <rtdk.h>
#include <rtdm/rtipc.h>
#include <iostream>
#include <thread>

#define XDDP_PORT_LABEL  "xddp-demo"
static const char *msg[] = {
    "Surfing With The Alien",
    "Lords of Karma",
    "Banana Mango",
    "Psycho Monkey",
    "Luminous Flesh Giants",
    "Moroccan Sunset",
    "Satch Boogie",
    "Flying In A Blue Dream",
    "Ride",
    "Summer Song",
    "Speed Of Light",
    "Crystal Planet",
    "Raspberry Jam Delta-V",
    "Champagne?",
    "Clouds Race Across The Sky",
    "Engines Of Creation"
};
static void fail(const char *reason) {
    perror(reason);
    exit(EXIT_FAILURE);
}
void realtime_thread1() {
    struct rtipc_port_label plabel;
    struct sockaddr_ipc saddr;
    char buf[128];
    int ret, s;
    /*
     * Get a datagram socket to bind to the RT endpoint. Each
     * endpoint is represented by a port number within the XDDP
     * protocol namespace.
     */
    s = socket(AF_RTIPC, SOCK_DGRAM, IPCPROTO_XDDP);
    if (s < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }
    /*
     * Set a port label. This name will be registered when
     * binding, in addition to the port number (if given).
     */
    strcpy(plabel.label, XDDP_PORT_LABEL);
    ret = setsockopt(s, SOL_XDDP, XDDP_LABEL,
                     &plabel, sizeof(plabel));
    if (ret)
        fail("setsockopt");
    /*
     * Bind the socket to the port, to setup a proxy to channel
     * traffic to/from the Linux domain. Assign that port a label,
     * so that peers may use a descriptive information to locate
     * it. For instance, the pseudo-device matching our RT
     * endpoint will appear as
     * /proc/xenomai/registry/rtipc/xddp/<XDDP_PORT_LABEL> in the
     * Linux domain, once the socket is bound.
     *
     * saddr.sipc_port specifies the port number to use. If -1 is
     * passed, the XDDP driver will auto-select an idle port.
     */
    memset(&saddr, 0, sizeof(saddr));
    saddr.sipc_family = AF_RTIPC;
    saddr.sipc_port = -1;
    ret = bind(s, (struct sockaddr *)&saddr, sizeof(saddr));
    if (ret)
        fail("bind");
    for (;;) {
        /* Get packets relayed by the regular thread */
        ret = recvfrom(s, buf, sizeof(buf), 0, NULL, 0);
        if (ret <= 0)
            fail("recvfrom");
        rt_printf("%s: "%.*s" relayed by peern", __FUNCTION__, ret, buf);
    }
}
void realtime_thread2() {
    struct rtipc_port_label plabel;
    struct sockaddr_ipc saddr;
    int ret, s, n = 0, len;
    struct timespec ts;
    struct timeval tv;
    socklen_t addrlen;
    s = socket(AF_RTIPC, SOCK_DGRAM, IPCPROTO_XDDP);
    if (s < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }
    /*
     * Set the socket timeout; it will apply when attempting to
     * connect to a labeled port, and to recvfrom() calls.  The
     * following setup tells the XDDP driver to wait for at most
     * one second until a socket is bound to a port using the same
     * label, or return with a timeout error.
     */
    tv.tv_sec = 1;
    tv.tv_usec = 0;
    ret = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO,
                     &tv, sizeof(tv));
    if (ret)
        fail("setsockopt");
    /*
     * Set a port label. This name will be used to find the peer
     * when connecting, instead of the port number.
     */
    strcpy(plabel.label, XDDP_PORT_LABEL);
    ret = setsockopt(s, SOL_XDDP, XDDP_LABEL,
                     &plabel, sizeof(plabel));
    if (ret)
        fail("setsockopt");
    memset(&saddr, 0, sizeof(saddr));
    saddr.sipc_family = AF_RTIPC;
    saddr.sipc_port = -1;   /* Tell XDDP to search by label. */
    ret = connect(s, (struct sockaddr *)&saddr, sizeof(saddr));
    if (ret)
        fail("connect");
    /*
     * We succeeded in making the port our default destination
     * address by using its label, but we don't know its actual
     * port number yet. Use getpeername() to retrieve it.
     */
    addrlen = sizeof(saddr);
    ret = getpeername(s, (struct sockaddr *)&saddr, &addrlen);
    if (ret || addrlen != sizeof(saddr))
        fail("getpeername");
    rt_printf("%s: NRT peer is reading from /dev/rtp%dn",
              __FUNCTION__, saddr.sipc_port);
    for (;;) {
        len = strlen(msg[n]);
        /*
         * Send a datagram to the NRT endpoint via the proxy.
         * We may pass a NULL destination address, since the
         * socket was successfully assigned the proper default
         * address via connect(2).
         */
        ret = sendto(s, msg[n], len, 0, NULL, 0);
        if (ret != len)
            fail("sendto");
        rt_printf("%s: sent %d bytes, "%.*s"n",
                  __FUNCTION__, ret, ret, msg[n]);
        n = (n + 1) % (sizeof(msg) / sizeof(msg[0]));
        /*
         * We run in full real-time mode (i.e. primary mode),
         * so we have to let the system breathe between two
         * iterations.
         */
        ts.tv_sec = 0;
        ts.tv_nsec = 500000000; /* 500 ms */
        clock_nanosleep(CLOCK_REALTIME, 0, &ts, NULL);
    }
}
void regular_thread() {
    char buf[128], *devname;
    int fd, ret;
    if (asprintf(&devname,
                 "/proc/xenomai/registry/rtipc/xddp/%s",
                 XDDP_PORT_LABEL) < 0)
        fail("asprintf");
    fd = open(devname, O_RDWR);
    std::cout << "File descriptor regular thread: " << fd << std::endl;
    free(devname);
    if (fd < 0)
        fail("open");
    for (;;) {
        /* Get the next message from realtime_thread2. */
        ret = read(fd, buf, sizeof(buf));
        if (ret <= 0)
            fail("read");
        /* Relay the message to realtime_thread1. */
        ret = write(fd, buf, ret);
        if (ret <= 0)
            fail("write");
    }
}
int main(int argc, char **argv) {
    std::thread rt1(realtime_thread1);
    std::thread rt2(realtime_thread2);
    std::thread regth(regular_thread);
    rt1.join();
    rt2.join();
    regth.join();
    return 0;
}

我在打开函数上失败,返回 -1。

我想用std::thread的原因是我需要在C++中实现代码,而 pthread 不理解成员函数。而且我不想使用全局变量。

此外,我需要在 RT 和 NRT(没有 xenomai 库)机器上运行相同的代码,并且我已经为此准备了代码(使用方便放置的#ifdef.

我已经想通了。我需要用Xenomai的posix皮肤包裹我的二进制文件。

在 CMAKE 中:

    set(xeno_cflags_params "--skin=posix" "--cflags")
execute_process(
    COMMAND xeno-config ${xeno_cflags_params}
    OUTPUT_VARIABLE xeno_cflags
    OUTPUT_STRIP_TRAILING_WHITESPACE)
set(xeno_ldflags_params "--skin=posix" "--ldflags")
execute_process(
    COMMAND xeno-config ${xeno_ldflags_params}
    OUTPUT_VARIABLE xeno_ldflags
    OUTPUT_STRIP_TRAILING_WHITESPACE)
# Compiler and linker options
set(CMAKE_C_FLAGS          "${CMAKE_CXX_FLAGS} ${xeno_cflags}")
set(CMAKE_CXX_FLAGS        "${CMAKE_CXX_FLAGS} ${xeno_cflags}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${xeno_ldflags}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${xeno_ldflags}")

最新更新