文件描述符集和选择理解 - 意外行为

时间:2015-04-23 07:39:02

标签: c++ c select set file-descriptor

我有一个第三方库,用于某种共享内存(进程之间)实现,带有一些预设数量的内存缓冲区。

流程分为readingwriting

此库为每个进程提供file-descriptor

我想使用库提供的一些代码示例(具有分开的读写功能的单个进程)来测试功能。代码示例有效,但我想了解这些文件描述符是什么以及它们是如何工作的。

这是基本代码示例(由我减少并评论)(使用4 shared buffers):

int fd1, fd2; // 2 file descriptors, fd1 for writing and fd2 for reading

SharedMemory_GetDescriptor(&fd1, options1); // options1 tells the library that fd1 will be used for writing data
SharedMemory_GetDescriptor(&fd2, options2); // options2 tells the library that fd2 will be used for reading data

fd_set readset, writeset; // fd_sets for later select commands

// empty the sets
FD_ZERO(&readset);
FD_ZERO(&writeset);

// find out whether writer may write
FD_SET(fd1, &writeset);
FD_SET(fd2, &readset); // WHY HAS THIS ONE TO BE SET??

// test which sets are "ready to read or write"
select(Maxfd+1, &readset, &writeset, NULL, &timeout); // maxfd is 1 bigger than fd1 and fd2, timeout is some small time value...

// if fd1 is ready to write, we can 
if (FD_ISSET(fd1, &writeset)) 
{
   if (SharedMemory_GetBuffer(&buffer1) == S_OK) 
   {
       [...] // write some values to the buffer provided by the shared memory
       SharedMemory_ReleaseBuffer(&buffer1); // tell the library, that this buffer was written?!?
   }
}

// if I repeat the steps FD_SET(fd1, writeset)->select->FD_ISSET(fd1, &writeset)->fillBufferAndRelease,
// the FD_ISSET fails for the 5th buffer, since we only have 4 buffers. This result was expected and works.

// now try to read the data by using the second file descriptor fd2

// add fd2 to readset
FD_SET(fd2, &readset);
// test whether fd2 is ready to be read
select(Maxfd+1, &readset, NULL, NULL, &timeout);

if (FD_ISSET(fd2, &readset)) 
    {
        if (SharedMemory_GetBuffer(&buffer2) == S_OK) 
        {
            [...] // read data from buffer provided by the shared memory
       SharedMemory_ReleaseBuffer(&buffer2); // tell the library, that this buffer was read?!?
        }
    }

这按预期工作,我可以写入1-4个缓冲区,然后从1-4个缓冲区读取。另外我可以例如首先写一个缓冲区,然后读一个,然后写一个,依此类推。

但有些事我没想到。根据我的理解,在开始写数据之前,

FD_SET(fd1, &writeset); 
FD_SET(fd2, &readset); 
select(Maxfd+1, &readset, &writeset, NULL, &timeout);

可以缩减为

FD_SET(fd1, &writeset); 
select(Maxfd+1, NULL, &writeset, NULL, &timeout);

因为我在写WRITE数据之前既不对readset感兴趣,也没有在select返回后fd2仍处于readset状态。

但是如果我更改为select(Maxfd+1, NULL, &writeset, NULL, &timeout);或者如果我删除了FD_SET(fd2, &readset);,则在阅读部分之前的select等到timeoutfd2不是&#39 ; t再次出现在readset

原因是什么? 据我所知,fd1和fd2是准备写还是准备读取取决于extern库的某些状态。但是,当我在本地将fd2添加到一个集合并要求它准备好阅读时,为什么这个库状态发生了变化,但它不是?

或者我误解了那些文件描述符和select?我在这个主题中真的很棒,无法找到很多信息/教程。

修改

尝试了更多的东西:

  • 在第一个writeset-select之前添加了一个FD_SET(fd2, &readset); select(fd2+1, &readset, NULL, NULL, &timeout);,并从第一个writeset-select中删除了readset部分。这确实有效,但不以任何方式回答这个问题。
  • 更改了getting the descriptors from the library的顺序,以便fd1是更大的数字。没有改变任何事情。
  • 在每次选择调用中将Maxfd更改为fd1fd2(因此,选择是使用fd1 + 1或fd2 + 1,具体取决于它是否用于捕获读取或写作就绪)但这并没有改变任何东西。

0 个答案:

没有答案