简体   繁体   English

使用nftw时如何避免使用全局变量

[英]How avoid using global variable when using nftw

I want to use nftw to traverse a directory structure in C. 我想使用nftw遍历C中的目录结构。

However, given what I want to do, I don't see a way around using a global variable. 但是,考虑到我想要做的事情,我没有看到使用全局变量的方法。

The textbook examples of using (n)ftw all involve doing something like printing out a filename. 使用(n)ftw的教科书示例都涉及执行类似打印文件名的操作。 I want, instead, to take the pathname and file checksum and place those in a data structure. 相反,我希望获取路径名和文件校验和并将它们放在数据结构中。 But I don't see a good way to do that, given the limits on what can be passed to nftw. 但考虑到可以传递给nftw的限制,我没有看到一个很好的方法。

The solution I'm using involves a global variable. 我正在使用的解决方案涉及一个全局变量。 The function called by nftw can then access that variable and add the required data. 然后,nftw调用的函数可以访问该变量并添加所需的数据。

Is there any reasonable way to do this without using a global variable? 没有使用全局变量有没有合理的方法呢?

Here's the exchange in previous post on stackoverflow in which someone suggested I post this as a follow-up. 这是关于stackoverflow的上一篇文章中的交换,有人建议我将其作为后续发布。

No. nftw doesn't offer any user parameter that could be passed to the function, so you have to use global (or static) variables in C. nftw不提供任何可以传递给函数的用户参数,因此您必须在C中使用全局(或静态)变量。

GCC offers an extension "nested function" which should capture the variables of their enclosing scopes, so they could be used like this: GCC提供了一个扩展“嵌套函数”,它应该捕获它们的封闭范围的变量,因此它们可以像这样使用:

void f()
{
  int i = 0;
  int fn(const char *,
    const struct stat *, int, struct FTW *) {
    i++;
    return 0;
  };
  nftw("path", fn, 10, 0);
}

Using ftw can be really, really bad . 使用ftw真的非常非常糟糕 Internally it will save the the function pointer that you use, if another thread then does something else it will overwrite the function pointer. 在内部,它将保存您使用的函数指针,如果另一个线程然后执行其他操作,它将覆盖函数指针。

Horror scenario: 恐怖场景:

 thread 1: count billions of files thread 2: delete some files thread 1: ---oops, it is now deleting billions of files instead of counting them. 

In short. 简而言之。 You are better off using fts_open. 你最好使用fts_open。

If you still want to use nftw then my suggestion is to put the "global" type in a namespace and mark it as "thread_local". 如果您仍想使用nftw,那么我的建议是将“全局”类型放在命名空间中并将其标记为“thread_local”。 You should be able to adjust this to your needs. 您应该能够根据您的需要进行调整。

/* in some cpp file */
namespace {
   thread_local size_t gTotalBytes{0};  // thread local makes this thread safe
int GetSize(const char* path, const struct stat* statPtr, int currentFlag, struct FTW* internalFtwUsage) {
    gTotalBytes+=  statPtr->st_size;
    return 0;  //ntfw continues
 }
} // namespace


size_t RecursiveFolderDiskUsed(const std::string& startPath) {
   const int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
   const int maxFileDescriptorsToUse = 1024; // or whatever
   const int result = nftw(startPath.c_str(), GetSize, maxFileDescriptorsToUse , flags);

  // log or something if result== -1
  return gTotalBytes;
}

The data is best given static linkage (ie file-scope) in a separate module that includes only functions required to access the data, including the function passed to nftw() . 数据最好在单独的模块中给出静态链接(即文件范围),该模块仅包括访问数据所需的函数,包括传递给nftw()的函数。 That way the data is not visible globally and all access is controlled. 这样,数据在全局范围内不可见,并且所有访问都受到控制。 It may be that the function that calls ntfw() is also part of this module, enabling the function passed to nftw() to also be static, and thus invisible externally. 可能是调用ntfw()的函数也是该模块的一部分,使传递给nftw()的函数也是静态的,因此在外部是不可见的。

In other words, you should do what you are probably doing already, but use separate compilation and static linkage judiciously to make the data only visible via access functions. 换句话说,你应该做你可能已经做过的事情,但是明智地使用单独的编译和静态链接来使数据仅通过访问函数可见。 Data with static linkage is accessible by any function within the same translation unit, and you avoid the problems associated with global variables by only including functions in that translation unit that are creators, maintainers or accessors of that data. 具有静态链接的数据可由同一翻译单元内的任何函数访问,并且通过仅包括该翻译单元中作为该数据的创建者,维护者或访问者的函数来避免与全局变量相关联的问题。

The general pattern is: 一般模式是:

datamodule.h datamodule.h

#if defined DATAMODULE_INCLUDE
<type> create_data( <args>) ;
<type> get_data( <args> ) ;
#endif

datamodule.c datamodule.c

#include "datamodule.h"

static <type> my_data ;

static int nftwfunc(const char *filename, const struct stat *statptr, int fileflags, struct FTW *pfwt)
{
    // update/add to my_data
    ...
}


<type> create_data( const char* path, <other args>)
{
    ...

    ret = nftw( path, nftwfunc, fd_limit, flags);

    ... 
}

<type> get_data( <args> )
{
    // Get requested data from my_data and return it to caller
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM