2015-05-09 138 views
-3

该程序假设根据用户提供的参数生成测试文件。该文件模拟具有第一参数fileNumber的命令。例如:C++测试文件生成器生成不一致的数据

START 1 
WRITE 1 1 
WRITE 1 1 
READ 1 1 
START 2 
READ 1 1 
... 
... 
READ 2 1 
END 1 
WRITE 1 2 
WRITE 1 2 
READ 2 2 
WRITE 1 1 
WRITE 1 2 
WRITE 1 2 
WRITE 2 3 
WRITE 2 4 
WRITE 2 5 
END 2 

的问题是,END fileNumber后的行不应该不再有对fileNumber任何更多的操作。

样品文本文件上面由发电机产生和演示此问题:线END 1后,仍然有多个WRITE 1 *

这里的代码:

int main(int argc, char **argv){ 
    if(argc < 4){ 
     usage(argv[0]); 
     exit(EXIT_FAILURE); 
    } 

    // extract command line arguments 
    std::stringstream ss; 
    int diskCapacity = atoi(argv[1]);// ss << argv[1]; ss >> diskCapacity; 
    int writeRatio = atoi(argv[2]);// ss << argv[2]; ss >> writeRatio; 
    char *ofileName = argv[3]; 

    // validate writeRatio 
    if((writeRatio < 0) || (writeRatio > 100)) { 
     std::cerr << argv[0] << ": writeRatio out of range [0,100]: " << writeRatio << std::endl; 
     exit(EXIT_FAILURE); 
    } 

    std::ofstream outfile; 
    outfile.open(ofileName); 

    // seed rng 
    std::chrono::high_resolution_clock::time_point time = std::chrono::high_resolution_clock::now(); 
    std::minstd_rand rng(time.time_since_epoch().count()); 

    /***** generate simluation sequence *****/ 
    int diskSize = 0; 
    std::vector<File> aliveFiles; 
    int new_fid = 1; 
    int nFilesCreated = 0; 

    // create at least 1 file 
    File f; 
    f.id = new_fid++; 
    f.size = 1; 
    aliveFiles.push_back(f); 
    diskSize++; 
    nFilesCreated++; 
    outfile << start(f.id) << std::endl; 

    do { 
     // start 
     if(((rng()%10) < 2) && (nFilesCreated < diskCapacity/4)){ 
     // new file 
     f.id = new_fid++; 
     f.size = 1; 

     // add to disk 
     aliveFiles.push_back(f); 
     diskSize++; 
     nFilesCreated++; 
     outfile << start(f.id) << std::endl; 
     continue; 
    } 

    // choose a file 
    int new_fsize = -1; 
    int new_fid = -1; 
    if(!aliveFiles.empty()) { 
     std::random_shuffle(aliveFiles.begin(), aliveFiles.end()); 
     new_fid = (aliveFiles.back()).id; 
     new_fsize = (aliveFiles.back()).size; 
    } 
    else { 
     break; 
    } 
    // write 
    if((int)(rng() % 100) < writeRatio) { 
     // writeRatio% chance to write 
     int block = 1 + (rng() % new_fsize); 
     File newFile; 
     if(block == new_fsize) { 
      // writing new block 
      diskSize++; 
      new_fsize++; 
      newFile.id = new_fid; 
      newFile.size = new_fsize; 
      aliveFiles.pop_back(); 
      aliveFiles.push_back(newFile); 
     } 
     outfile << write(newFile.id, block) << std::endl; 
     continue; 
    } 

    // end/read 
    if(rng() % 100 == 0) { 
     // end 
     aliveFiles.pop_back(); 
     outfile << end(new_fid) << std::endl; 
    } 
    else { 
     if((int)(rng() % 100) < (100-writeRatio)){ 
      // (100-writeRatio)% chance to read 
      if(new_fsize > 1) { 
       int block = 1 + (rng() % (new_fsize-1)); 
       outfile << read(new_fid, block) << std::endl; 
      } 
     } 
    } 
    } while(diskSize < diskCapacity); 

    // check that all files have ended, if not then clean up 
    while(!aliveFiles.empty()) { 
     new_fid = (aliveFiles.back()).id; 
     aliveFiles.pop_back(); 
     outfile << end(new_fid) << std::endl; 
    } 

    return 0; 
} 

回答

1

误差是相当恶劣的。如果您查看测试数据,您会注意到坏的文件编号只发生在WRITE行,而从来没有发生过READ行。

这缩小了问题你的代码,您使用的变量newFile没有先初始化它的这一部分:

// write 
    if((int)(rng() % 100) < writeRatio) { 
     // writeRatio% chance to write 
     int block = 1 + (rng() % new_fsize); 
     File newFile;      // <===== unitialized !! 
     if(block == new_fsize) {   // <===== what happens if this is false ? 
      // writing new block 
      diskSize++; 
      new_fsize++; 
      newFile.id = new_fid; 
      newFile.size = new_fsize; 
      aliveFiles.pop_back(); 
      aliveFiles.push_back(newFile); 
     } 
    outfile << write(newFile.id, block) << std::endl; // <== OUCH, if the if condition failed you go here with random data in newFile !! 
     continue; 
    } 

两个备选方案来解决这个问题:

  • 只需推动outfile<< ... ;声明到if区块。生成的测试文件然后完全可靠并且一致。但是WRITE仅在block==new_fsize时才会发生。
  • 或者在if块之外移动newFile.id=new_fid;和​​。但是你必须考虑是否可以在newFile.id上“书写”而不将其放入aliveFiles中。
+0

好的。我花了整晚,没有找到这个bug。 – firefly

+1

@firefly小心new_fid变量。它被定义了两次,一次在do/while之外,一次在。可能不是你想要的。 – user4581301

+0

@ user4581301这太棒了!恭喜!而且非常讨厌:循环体的第一部分引用循环外部的new_fid,但是循环的第二部分移植到重新定义的部分。你可能在另一个夜晚保存了萤火虫 – Christophe