我有一个测试用例(更大的应用程序的剥离版本)在尝试删除目录或文件时偶尔会在Windows 7计算机上失败。它使用本机Windows API。 测试执行以下步骤 -
如果您跳过步骤#1,那么测试运行正常。 如果在步骤#4和步骤#5之间添加延迟,则测试运行正常。
#include <windows.h>
#include <string>
#include <iostream>
#include <stdio.h>
#include <direct.h>
#include <sqlite3.h>
#include <io.h>
using namespace std;
bool sleep_for_sometime = false;
bool create_table = false;
bool runTest()
{
char cwdpath[1024] = {'\0'};
if (_getcwd(cwdpath, 1023) == NULL) return false;
string testpath(cwdpath);
testpath += "/test_dir";
_mkdir(testpath.c_str());
string dbpath = testpath + "/test.db";
sqlite3 *db = NULL;
if (sqlite3_open(dbpath.c_str(), &db) != SQLITE_OK) return false;
// Create table.
if (create_table) {
string sql = "CREATE TABLE COMPANY(" \
"ID INT PRIMARY KEY NOT NULL," \
"NAME TEXT NOT NULL," \
"AGE INT NOT NULL)";
char *zErrMsg = 0;
if (sqlite3_exec(db, sql.c_str(), NULL, 0, &zErrMsg) != SQLITE_OK) {
sqlite3_close(db);
cerr << "Could not create table: " << zErrMsg << endl;
return false;
}
}
sqlite3_close(db);
if (sleep_for_sometime) {
Sleep(100);
}
string journal_file = dbpath + "-journal";
string journal_error = journal_file + " failed";
if (_access(journal_file.c_str(), 06) == 0) {
if (_unlink(journal_file.c_str()) != 0) {
perror(journal_error.c_str());
return false;
}
cout << "journal file --" << journal_file << endl;
}
string db_error = dbpath + " failed";
if (_unlink(dbpath.c_str()) != 0) {
perror(db_error.c_str());
return false;
}
string dir_error = testpath + " failed";
if (_rmdir(testpath.c_str()) != 0) {
perror(dir_error.c_str());
return false;
}
return true;
}
int main(int argc, char **argv)
{
cout << "Usage: ./projtest 1 1" << endl;
cout << "------If you pass two parameter, then always create table and sleep for some time." << endl;
cout << "Usage: ./projtest 1" << endl;
cout << "------If you pass one parameter, then always create table, but don't sleep." << endl;
cout << "Usage: ./projtest" << endl;
cout << "------If you don't pass any parameter, then don't create table and don't sleep." << endl;
if (argc == 3) {
sleep_for_sometime = true;
create_table = true;
} else if (argc == 2) {
create_table = true;
sleep_for_sometime = false;
} else {
create_table = false;
sleep_for_sometime = false;
}
for (int i = 0; i < 500 ; i++) {
if (! runTest()) {
cerr << "Err in runTest trial --" << i+1 << endl;
return 1;
}
}
return 0;
}
答案 0 :(得分:0)
可能是活动文件锁sqllite强制它在步骤4和5之间没有及时清除。 请记住,与硬盘相比,内存中的代码以闪存速度运行。 对硬盘的sql lite进程指令很可能仍然忙于将数据写入文件,在日志中输入条目,然后释放文件处理程序,而代码已经忙于删除它。
因此,虽然sql lite完成并且使用了,但是硬盘仍在勾选其写入数据和清除锁定的工作列表。
也许你可以实现一个while循环来检查文件是否被锁定,然后耐心地等待释放锁,或者标记文件以备将来删除并每50ms重新检查一次。
修改强> 补充澄清
事情是这里有两个问题。硬盘速度和CPU速度。在正常的程序代码中,当您将写入指令推送到硬盘时,它将被放入驱动程序/驱动器本身的队列中以进行写入,并且驱动程序/硬盘一个接一个地工作(ish)。
程序将收到一条消息,表明操作已经被调整,因此可以继续执行。为什么程序在继续正确之前必须等待一两毫秒?由于硬盘驱动器很慢并且有自己的优先级来阅读和写东西。它会做到这一点,但现在不完全导致它现在正在读取文件或其他东西。
因此,虽然文件可以自由编辑的写入操作仍然在要写入的队列中,但它已经发送了删除请求,但该文件尚未被标记为可写,因为该操作仍在队列中。而错误来自。