我想生成1到10万个数字,以获取我的文件名的唯一ID。为了实现这一点,我使用lock创建了一个静态属性,如下所示: -
private static readonly object objLock = new object();
private static int _statInt = 1;
private static string statInt
{
get
{
lock (objLock)
{
if (_statInt >= 100000)
{
_statInt = 1;
}
else
{
_statInt = _statInt + 1;
}
return "_" + _statInt.ToString();
}
}
}
注意我不想生成唯一的id throw guid,因为它可能是重复的或日期时间的组合[我试过它都创建了重复]。在我的情况下,如果上面的方法在10万之后失败,它就是我的文件。[如上面的代码我将用于唯一的文件名,文件创建一个大约5000,然后它被删除]
第一个问题上述代码线程是否安全?
如果是,那么我的第二个原始问题从这里开始: -
我只是在这里保留完整的代码以更好地理解这个问题: -
class Program
{
static void Main(string[] args)
{
_Interfaceupload obj = new _Interfaceupload();
for (int i = 0; i < 100000; i++)
{
Thread thrd = new Thread(obj.getFileNoDuplicate);
thrd.Start();
}
Console.ReadLine();
Dictionary<string, string> obj0 = _Interfaceupload.objDic;
Console.ReadLine();
}
}
class _Interfaceupload
{
private static readonly object objLock = new object();
private static int _statInt = 0;
private static string _fileName = "C:/TEST/vikas";
private static string _InitfileName = "C:/TEST/vikas";
private static string statInt
{
get
{
lock (objLock)
{
if (_statInt > 100000)
{
_statInt = 0;
}
else
{
_statInt = _statInt + 1;
}
return "_" + _statInt.ToString();
}
}
}
public static string stateDate
{
get
{
return "_" + DateTime.Now.Ticks.ToString() + "_" + System.Guid.NewGuid();
}
}
public static Dictionary<string, string> objDic = new Dictionary<string, string>();
public void getFileNoDuplicate()
{
try
{
//objDic.Add(_InitfileName + statInt, string.Empty);
// _fileName = _InitfileName + stateDate;
_fileName = _InitfileName + statInt;
objDic.Add(FileManager2.Write(_fileName, "txt", "hello", false), string.Empty);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
class FileManager2
{
public static string Write(string file, string ext, string data, bool overwrite)
{
return (string)OperateOnFile(file, ext, data, overwrite);
}
private static object OperateOnFile(string file, string ext,
string data, bool overWrite)
{
StreamReader sr = null;
StreamWriter sw = null;
string workingFile = null;
string dir = null;
try
{
workingFile = file + "." + ext;
if (overWrite == false && File.Exists(workingFile))
{
workingFile = (string)OperateOnFile(workingFile + System.Guid.NewGuid().ToString(), ext, data, overWrite);
}
else
{
dir = "C:/TEST/";
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
sw = new StreamWriter(File.Open(workingFile, FileMode.Create, FileAccess.Write, FileShare.None), Encoding.UTF8);
sw.Write(data);
}
return workingFile;
}
finally
{
if (sr != null)
sr.Close();
if (sw != null)
{
sw.Flush();
sw.Close();
}
}
}
}
(可能需要跟随namespaces
包含)
using System.Threading;
using System.IO;
第二个问题:当我在控制台应用程序(.NET framework 4.5)中运行它时,对于10万条记录,它看起来该文件正在重复,因为我得到异常&#34;文件正在使用另一个进程&#34;但是如果第一个代码是线程安全的,那么它不应该创建重复的id直到10万。这里有什么问题,我称呼它的方式?或者StreamWriter类或代码问题绕过线程?不确定请告知。
注意我无法锁定File.Exists
方法。
被修改 在MarvinSmit的评论使方法成为非静态
之后 private string _fileName = "C:/TEST/vikas";
private string _InitfileName = "C:/TEST/vikas";
还删除了词典并将其修改如下: -
public void getFileNoDuplicate()
{
try
{
//objDic.Add(_InitfileName + statInt, string.Empty);
// _fileName = _InitfileName + stateDate;
_fileName = _InitfileName + statInt;
FileManager2.Write(_fileName, "txt", "hello", false);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
此后也没有工作。
解决方案
OMG !!我得到了罪魁祸首...以下代码行的问题
_fileName = _InitfileName + statInt;
我已删除此行,并直接将其传递给方法。
public void getFileNoDuplicate()
{
try
{
FileManager2.Write(_fileName + statInt, "txt", "hello", false);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
这是一个疯狂的错误,我创建了一个类的单个实例并将其传递给整个线程,
我很欣赏马文的评论,
&#34; _fileName = _InitfileName + statInt;在以线程安全的方式写入时不被锁定被读取可能导致重复。&#34;
他很快就注意到了,但我们后来都走向了不同的方向。感谢大家的评论
答案 0 :(得分:0)
无论您在FileStream
文件周围放置多少锁,都无法同时打开多次。这包括可能打开文件的其他应用程序。您收到的异常告诉您,您尝试多次打开同一个文件 - 您的路径随机化代码已损坏。
有一些例外 - 使用明确file share level打开的文件。
您对FileManager2.OperateOnFile
的每次通话都会尝试打开该文件。每个电话都是一个不同的线程。
sw = new StreamWriter(File.Open(workingFile, FileMode.Create, FileAccess.Write, FileShare.None), Encoding.UTF8);
你有什么理由不能使用System.IO.Path.GetTempFileName
吗?它专为您的情况而设计。
在磁盘上创建一个唯一命名的零字节临时文件并返回 该文件的完整路径。
http://msdn.microsoft.com/en-us/library/system.io.path.gettempfilename%28v=vs.110%29.aspx
答案 1 :(得分:0)
我认为你的问题在这里:
您将_fileName
标记为static
private static string _fileName = "C:/TEST/vikas";
然后你有多个线程在这里为它分配一个值:
public void getFileNoDuplicate()
{
try
{
//objDic.Add(_InitfileName + statInt, string.Empty);
// _fileName = _InitfileName + stateDate;
_fileName = _InitfileName + statInt;
objDic.Add(FileManager2.Write(_fileName, "txt", "hello", false), string.Empty);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
一个线程可能会设置它,然后另一个线程将再次设置它,然后两个线程将尝试写入同一个文件。放下static
,你就会朝正确的方向走。
但是,我同意古斯多的观点,你应该调查Parallel.For()
和Path.GetTempFileName()
。
答案 2 :(得分:0)
我认为您可以使用以下代码(.Net 4 +)
来实现您的目标 private static string _basePath = "C:/TEST/vikas/";
static void Main(string[] args)
{
Parallel.For(0, 10000, (index) =>
{
string filename = Path.Combine(_basePath, "_" + index.ToString());
// filename is unique
}
);
}
希望这有帮助。