2016-02-11 119 views
0

我需要在Xenomai機器上執行RT到NRT通信。xenomai xddp與std :: thread

我居然能編譯和運行提出here 的例子但是,如果試圖將pthreadsstd::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 peer\n", __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%d\n", 
       __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; 
} 

我在open函數,它返回會出現故障 - 1。

我想使用std::thread的原因是我需要在C++中實現代碼,並且pthread不理解成員函數。我不想使用全局變量。

另外,我需要運行在RT和NRT相同的代碼(不xenomai庫)機,我已經準備了代碼(方便擺放#ifdef

+0

從我讀過有關Xenomai它給線程個性層,如果你使用POSIX線程,這那麼C++ std :: thread會得到一個Po六層,你不能使用Xenomai功能。 –

+0

即使使用'pthread_create()',也可以調用C++成員函數,例如,您希望在C++'std :: thread'下找到什麼? –

回答

2

我已經想通了。 我需要換我二進制與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}") 
相關問題