■結論
自前でlockする方法が安全。
lockした場合でもエディタ等で開くと例外が発生するので注意。 TextWriter.Synchronized()の有用性は不明。 以下に試したコードを記載する。
当然だが、log4net等のライブラリを使うのがベスト。どうしても使えない事情がある場合のみ自前でlockを行うこと。
■lockを使用
自前でlockする方法が安全。
lockした場合でもエディタ等で開くと例外が発生するので注意。 TextWriter.Synchronized()の有用性は不明。 以下に試したコードを記載する。
当然だが、log4net等のライブラリを使うのがベスト。どうしても使えない事情がある場合のみ自前でlockを行うこと。
■lockを使用
- コード
using System;
using System.Text;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace MultiThreadFileWrite
{
class Program
{
static void Main(string[] args)
{
string path = @"c:\tmp\log.txt";
string errPath = @"c:\tmp\err_";
object lockObj = new object(); // 状況次第でインスタンス変数にして、staticにすること。
try
{
Parallel.For(0, 10, (name) =>
{
try
{
for (int i = 0; i < 10000; i++)
lock (lockObj)
using (StreamWriter sw = new StreamWriter(path, true, Encoding.GetEncoding("Shift_JIS")))
sw.WriteLine("0x" + Thread.CurrentThread.ManagedThreadId.ToString("X8") + ":" + i);
}
catch (Exception ex)
{
File.WriteAllText(errPath + Path.GetRandomFileName(), ex.Message + Environment.NewLine + ex.StackTrace);
}
});
}
catch (Exception ex)
{
File.WriteAllText(errPath + Path.GetRandomFileName() + ".log", ex.Message + Environment.NewLine + ex.StackTrace);
}
}
}
}
- 結果 10万行全て正しい。
■TextWriter.Synchronized + ReadWrite (稀にファイル書き込みに抜けがある)
0(00000009):2632
5(0000000A):12
5(0000000A):13
0(00000009):2634
■TextWriter.Synchronized + append=true(例外が発生する)
- コード
using System;
using System.Text;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace MultiThreadFileWrite
{
class Program
{
static void Main(string[] args)
{
string path = @"c:\tmp\log.txt";
string errPath = @"c:\tmp\err_";
try
{
Parallel.For(0, 10, (name) =>
{
try
{
for (int i = 0; i < 10000; i++)
using (FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
using (StreamWriter sw = new StreamWriter(fs, Encoding.GetEncoding("Shift_JIS")))
using (TextWriter tw = TextWriter.Synchronized(sw))
tw.WriteLine(name + "(" + Thread.CurrentThread.ManagedThreadId.ToString("X8") + "):" + i);
}
catch (Exception ex)
{
File.WriteAllText(errPath + Path.GetRandomFileName(), ex.Message + Environment.NewLine + ex.StackTrace);
}
});
}
catch (Exception ex)
{
File.WriteAllText(errPath + Path.GetRandomFileName() + ".log", ex.Message + Environment.NewLine + ex.StackTrace);
}
}
}
}
- 結果(抜粋)
0(00000009):2632
5(0000000A):12
5(0000000A):13
0(00000009):2634
■TextWriter.Synchronized + append=true(例外が発生する)
- コード
using System;
using System.Text;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace MultiThreadFileWrite
{
class Program
{
static void Main(string[] args)
{
string path = @"c:\tmp\log.txt";
string errPath = @"c:\tmp\err_";
try
{
Parallel.For(0, 10, (name) =>
{
try
{
for (int i = 0; i < 10000; i++)
using (StreamWriter sw = new StreamWriter(path, true, Encoding.GetEncoding("Shift_JIS")))
using (TextWriter tw = TextWriter.Synchronized(sw))
tw.WriteLine(Thread.CurrentThread.Name + ":" + i);
}
catch (Exception ex)
{
File.WriteAllText(errPath + Path.GetRandomFileName(), ex.Message + Environment.NewLine + ex.StackTrace);
}
});
}
catch (Exception ex)
{
File.WriteAllText(errPath + Path.GetRandomFileName() + ".log", ex.Message + Environment.NewLine + ex.StackTrace);
}
}
}
}
- 結果(抜粋) 別のプロセスで使用されているため、プロセスはファイル 'c:\tmp\log.txt' に アクセスできません。
0 件のコメント:
コメントを投稿