You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在不支持FIOCANCEL的VxWorks环境中如何安全关闭文件描述符?

Safe Ways to Close a File Descriptor in VxWorks (Without FIOCANCEL)

Got it, let's work through this problem since FIOCANCEL isn't available in your VxWorks setup. Here are three practical, reliable workarounds to safely close a file descriptor that's tied up in a blocking read from another task:

1. Timeout-Based Polling with an Exit Flag

Instead of letting your read task block indefinitely on read(), use select() with a short timeout to periodically check if it's time to exit. This gives you a clean way to signal the read task to shut down before closing the FD.

Implementation Steps:

  • Create a volatile, thread-safe exit flag (use a mutex or spinlock to protect access if multiple tasks might modify it):
    volatile int g_shouldExitReadTask = 0;
    SEM_ID g_exitFlagMutex = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE);
    
  • Modify the read task to use select() with a timeout instead of blocking read():
    fd_set readFds;
    struct timeval tv;
    ssize_t bytesRead;
    char buffer[BUFFER_SIZE];
    
    while (1) {
        // Setup select set and timeout
        FD_ZERO(&readFds);
        FD_SET(targetFd, &readFds);
        tv.tv_sec = 1; // Adjust timeout to fit your needs
        tv.tv_usec = 0;
    
        int selectRet = select(targetFd + 1, &readFds, NULL, NULL, &tv);
        if (selectRet > 0 && FD_ISSET(targetFd, &readFds)) {
            // Data available: perform read
            bytesRead = read(targetFd, buffer, BUFFER_SIZE);
            if (bytesRead <= 0) {
                // Error or EOF: exit loop
                break;
            }
            // Process your data here...
        } else if (selectRet == 0) {
            // Timeout: check exit flag
            semTake(g_exitFlagMutex, WAIT_FOREVER);
            int exitNow = g_shouldExitReadTask;
            semGive(g_exitFlagMutex);
    
            if (exitNow) {
                break;
            }
        } else {
            // Select failed: handle error and exit
            break;
        }
    }
    // Cleanup resources in read task before exiting
    
  • In your close task, set the exit flag, wait for the read task to terminate, then close the FD:
    // Signal read task to exit
    semTake(g_exitFlagMutex, WAIT_FOREVER);
    g_shouldExitReadTask = 1;
    semGive(g_exitFlagMutex);
    
    // Wait for read task to finish (use taskJoin if the task is joinable)
    taskJoin(readTaskId, WAIT_FOREVER);
    
    // Now safely close the FD
    close(targetFd);
    

2. Pipe-Based Wakeup Mechanism

This is a more efficient alternative to polling: use a pipe to instantly wake up the read task when you need to close the FD. The read task listens for both the target FD and the pipe's read end via select().

Implementation Steps:

  • Create a pipe for inter-task communication:
    int wakeupPipe[2];
    if (pipe(wakeupPipe) != OK) {
        // Handle pipe creation error
        return ERROR;
    }
    
  • Modify the read task to monitor both the target FD and the pipe:
    fd_set readFds;
    int maxFd = max(targetFd, wakeupPipe[0]) + 1;
    char buffer[BUFFER_SIZE];
    char dummy;
    
    while (1) {
        FD_ZERO(&readFds);
        FD_SET(targetFd, &readFds);
        FD_SET(wakeupPipe[0], &readFds);
    
        int selectRet = select(maxFd, &readFds, NULL, NULL, NULL);
        if (selectRet > 0) {
            if (FD_ISSET(targetFd, &readFds)) {
                // Process data from target FD
                ssize_t bytesRead = read(targetFd, buffer, BUFFER_SIZE);
                if (bytesRead <= 0) break;
                // Handle data...
            }
            if (FD_ISSET(wakeupPipe[0], &readFds)) {
                // Wakeup signal received: exit loop
                read(wakeupPipe[0], &dummy, 1); // Clear pipe data
                break;
            }
        } else {
            // Select error: exit
            break;
        }
    }
    // Cleanup pipe read end in read task
    close(wakeupPipe[0]);
    
  • In the close task, send a wakeup signal via the pipe, wait for the read task to exit, then close the FD:
    // Send wakeup signal to read task
    write(wakeupPipe[1], "x", 1);
    close(wakeupPipe[1]);
    
    // Wait for read task to terminate
    taskJoin(readTaskId, WAIT_FOREVER);
    
    // Safely close the target FD
    close(targetFd);
    

This method avoids polling overhead and wakes the read task immediately when needed.

3. Task Signal to Interrupt Blocking read()

VxWorks allows you to send a signal to a task to interrupt blocking system calls like read(). When the read task receives the signal, read() will return -1 with errno set to EINTR, letting you exit the read loop.

Implementation Steps:

  • Ensure the read task doesn't block the signal you'll use (e.g., SIGUSR1):
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGUSR1);
    sigprocmask(SIG_UNBLOCK, &mask, NULL);
    
  • Modify the read task to handle interrupted reads:
    char buffer[BUFFER_SIZE];
    while (1) {
        ssize_t bytesRead = read(targetFd, buffer, BUFFER_SIZE);
        if (bytesRead < 0) {
            if (errno == EINTR) {
                // Read was interrupted by signal: exit loop
                break;
            }
            // Handle other errors
            break;
        } else if (bytesRead == 0) {
            // EOF received: exit
            break;
        }
        // Process data...
    }
    
  • In the close task, send the signal to the read task, wait for it to exit, then close the FD:
    // Send signal to interrupt read task
    taskSignal(readTaskId, SIGUSR1);
    
    // Wait for read task to finish
    taskJoin(readTaskId, WAIT_FOREVER);
    
    // Close the FD safely
    close(targetFd);
    

Note: Not all device drivers support interrupting read() with signals. Test this with your specific hardware/driver first.


Recommendation

The pipe-based wakeup method is generally the best choice—it's efficient, reliable, and avoids the overhead of polling or potential signal compatibility issues. The timeout method works well if pipes aren't an option, while the signal method is a last resort for drivers that support it.

内容的提问来源于stack exchange,提问作者Mrchacha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 06:23:20