In the process of developing a program, the key function of writing error log is unavoidable. To implement this feature, you can choose to use a third-party log plug-in, or you can choose to use a database, and you can write an easy way to log the error message to the file.
When you select the last method implementation, the problem may occur if you are unfamiliar with the file operation, because the same file does not allow multiple threads to write at the same time, or you will be prompted to " file is being used by another process, so the process cannot access this file ."
This is a concurrent write problem for a file and requires thread synchronization. And Microsoft also gives the thread synchronization to provide some related classes can achieve this purpose, this article uses the System.Threading.ReaderWriterLockSlim is one of them.
This class is used to manage the lock state of resource access, which enables multi-threaded reads or exclusive write access. With this class, we can avoid concurrent write problems caused by multiple threads writing to a file at the same time.
Read-write locks are managed using ReaderWriterLockSlim objects as locks, and locking the same file in different ReaderWriterLockSlim objects is treated as a different lock. This difference may cause a concurrent write problem to the file again, so ReaderWriterLockSlim should be defined as a read-only static object.
ReaderWriterLockSlim has several key methods, this article discusses only write locks:
The call to the Enterwritelock method enters the write state and is blocked until the calling thread enters the lock, and therefore may never return .
Call the Tryenterwritelock method into the write state to specify the blocking interval, which returns false if the calling thread did not enter write mode during this interval.
Calling the Exitwritelock method exits the write state, you should use the finally block to execute the Exitwritelock method to ensure that the caller exits write mode.
Don ' t talk, show me the code.
1. Multithreading write files at the same time
Class program
{
static int logcount = m;
static int writedcount = 0;
static int failedcount = 0;
static void Main (string[] args)
{
//iterations run write logging, because multiple threads writing the same file at the same time will cause error
parallel.for (0, Logcount, e =>
{
writelog ();
});
Console.WriteLine (String. Format ("\r\nlog count:{0}.\t\twrited count:{1}.\tfailed count:{2}.", Logcount.tostring (), writedcount.tostring (), Failedcount.tostring ()));
Console.read ();
}
static void Writelog ()
{
try
{
var logfilepath = ' Log.txt ';
var now = DateTime.Now;
var logcontent = string. Format ("Tid: {0}{1} {2}.{ 3}\r\n ", Thread.CurrentThread.ManagedThreadId.ToString (). PadRight (4), now. Tolongdatestring (), now. Tolongtimestring (), now.Millisecond.ToString ());
File.appendalltext (LogFilePath, logcontent);
writedcount++;
}
catch (Exception ex)
{
failedcount++;
Console.WriteLine (ex. message);}}
Run Result:
No read-write locks are used and only some of the logs are successfully written to the log file.
2. Multithreading writes files by using read-write locks
Class Program {static int logcount = 100;
static int writedcount = 0;
static int failedcount = 0;
static void Main (string[] args) {//Iteration run write logging parallel.for (0, Logcount, e => {writelog ();
}); Console.WriteLine (String. Format ("\r\nlog count:{0}.\t\twrited count:{1}.\tfailed count:{2}.", Logcount.tostring (), writedcount.tostring (),
Failedcount.tostring ()));
Console.read ();
}//Read-write lock, when the resource is in write mode, other threads write to the static ReaderWriterLockSlim Logwritelock = new ReaderWriterLockSlim () after writing to wait for this write to finish; static void Writelog () {try {///Set read-write locks to write-mode exclusive resources, other write requests need to wait until the end of this write to continue writing//Note: Holding a reader lock or writer lock for a long time can cause hunger (starve) to occur for other threads.
For best performance, consider the need to reconstruct the application to minimize the duration of write access. From a performance point of view, the request into write mode should immediately precede the file operation, where the write mode is entered only to reduce code complexity/Because the entry and exit write mode should be within the same try finally statement block, so the exception cannot be triggered until the request enters write mode.
Otherwise the number of releases is greater than the number of requests will trigger an exception logwritelock.enterwritelock ();
var LogFilePath = "Log.txt";
var now = DateTime.Now; var logcontent = string. Format ("Tid: {0}{1} {2}.{ 3}\r\n ", Thread.CurrentThread.ManagedThreadId.ToString (). PadRight (4), now. Tolongdatestring (), now.
Tolongtimestring (), now.Millisecond.ToString ());
File.appendalltext (LogFilePath, logcontent);
writedcount++;
catch (Exception) {failedcount++; finally {//exit write mode, free up resource occupancy//NOTE: One request for one release//if the number of releases is greater than the number of requests will trigger an exception [write lock is released without remaining]////If not released after processing of the request will trigger an exception [this mode does not allow recursive access to write
Lock] Logwritelock.exitwritelock ();
}
}
}
Run Result:
Using read-write locks, all logs are successfully written to the log file.
3. Testing in complex multithreaded environments using read-write locks to write files synchronously
Class Program {static int logcount = 1000;
static int sumlogcount = 0;
static int writedcount = 0;
static int failedcount = 0;
static void Main (string[] args) {//To line Cheng Chili Add a task, the iteration writes n logs sumlogcount + = Logcount;
ThreadPool.QueueUserWorkItem (obj) => {parallel.for (0, Logcount, e => {writelog ();
});
});
In the new thread, add n write log task to thread pool Sumlogcount + = Logcount;
var thread1 = new Thread (() => {parallel.for (0, Logcount, e => {threadpool.queueuserworkitem (subobj) => {
Writelog ();
});
});
}); Thread1.
IsBackground = false; Thread1.
Start ();
Add n write to log task to thread pool Sumlogcount + = Logcount;
Parallel.For (0, Logcount, e => {threadpool.queueuserworkitem (obj) => {writelog ();
});
});
In the new thread, the iteration writes n logs sumlogcount + = Logcount;
var thread2 = new Thread (() => {parallel.for (0, Logcount, e => {writelog ();
});
}); Thread2.
IsBackground = false; Thread2.
Start ();
In the current thread, the iteration writes n logs sumlogcount + = Logcount; Parallel.For (0, Logcount, e =&Gt
{Writelog ();
});
Console.WriteLine ("Main Thread processed.\r\n"); while (true) {Console.WriteLine (string. Format ("Sum Log count:{0}.\t\twrited count:{1}.\tfailed count:{2}.", Sumlogcount.tostring (), writedcount.tostring (),
Failedcount.tostring ()));
Console.ReadLine ();
}//Read/write lock, when the resource is in write mode, other threads write to the static ReaderWriterLockSlim Logwritelock = new ReaderWriterLockSlim () after writing to wait for this write to finish; static void Writelog () {try {///Set read-write locks to write-mode exclusive resources, other write requests need to wait until the end of this write to continue writing//Note: Holding a reader lock or writer lock for a long time can cause hunger (starve) to occur for other threads.
For best performance, consider the need to reconstruct the application to minimize the duration of write access. From a performance point of view, the request into write mode should immediately precede the file operation, where the write mode is entered only to reduce code complexity/Because the entry and exit write mode should be within the same try finally statement block, so the exception cannot be triggered until the request enters write mode.
Otherwise the number of releases is greater than the number of requests will trigger an exception logwritelock.enterwritelock ();
var LogFilePath = "Log.txt";
var now = DateTime.Now; var logcontent = string. Format ("Tid: {0}{1} {2}.{ 3}\r\n ", Thread.CurrentThread.ManagedThreadId.ToString (). PadRight (4), now. Tolongdatestring (), now.
Tolongtimestring (), now.Millisecond.ToString ()); File.appendalltext (Logfilepath, logcontent);
writedcount++;
catch (Exception) {failedcount++; finally {//exit write mode, free up resource occupancy//NOTE: One request for one release//if the number of releases is greater than the number of requests will trigger an exception [write lock is released without remaining]////If not released after processing of the request will trigger an exception [this mode does not allow recursive access to write
Lock] Logwritelock.exitwritelock ();
}
}
}
Run Result:
Partial log file contents:
... TID:36 December 11, 2016 15:29:22.825 tid:29 December 11, 2016 15:29:22.830 tid:6 December 11, 2016 15:29:22.838 tid:26 December 11, 2016 15:2 9:22.845 tid:34 December 11, 2016 15:29:22.854 tid:24 December 11, 2016 15:29:22.863 tid:27 December 11, 2016 15:29:22.872 tid:14 2016 1 February 11 15:29:22.877 tid:23 December 11, 2016 15:29:22.886 tid:20 December 11, 2016 15:29:22.892 tid:30 December 11, 2016 15:29:22.898 Tid: 9 December 11, 2016 15:29:22.904 tid:21 December 11, 2016 15:29:22.909 tid:22 December 11, 2016 15:29:22.915 tid:7 December 11, 2016 15:29:22. 920 Tid:3 December 11, 2016 15:29:22.925 tid:12 December 11, 2016 15:29:22.931 tid:5 December 11, 2016 15:29:22.937 tid:13 December 11, 2016 1 5:29:22.942 tid:11 December 11, 2016 15:29:22.947 tid:19 December 11, 2016 15:29:22.953 tid:37 December 11, 2016 15:29:22.958 tid:37 201 6 year December 11 15:29:22.964 tid:40 December 11, 2016 15:29:22.970 tid:40 December 11, 2016 15:29:22.975 tid:40 December 11, 2016 15:29:22.980 T ID:40 December 11, 2016 15:29:22.985 tid:40 December 11, 2016 15:29:22.991 tid:40 December 11, 2016 15:29:22.997 tid:31 December 11, 2016 15:2 9:23.3 tid:31 2016 year December 11 15:29:23.9 tid:31 December 11, 2016 15:29:23.14 tid:31 December 11, 2016 15:29:23.20 tid:31 December 11, 2016 15:29:23.27 Tid:3
1 December 11, 2016 15:29:23.33 tid:31 December 11, 2016 15:29:23.38 tid:31 December 11, 2016 15:29:23.44 tid:31 December 11, 2016 15:29:23.49 Tid:31 December 11, 2016 15:29:23.57 tid:31 December 11, 2016 15:29:23.63 tid:31 December 11, 2016 15:29:23.68 tid:31 December 11, 2016 15:29: 23.74 tid:16 December 11, 2016 15:29:23.80 tid:16 December 11, 2016 15:29:23.86 tid:16 December 11, 2016 15:29:23.93 tid:16 December 11, 2016 15:29:23.99 tid:16 December 11, 2016 15:29:23.105 tid:16 December 11, 2016 15:29:23.110 tid:16 December 11, 2016 15:29:23.116 tid:38 201 6 year December 11 15:29:23.122 tid:38 December 11, 2016 15:29:23.128 tid:28 December 11, 2016 15:29:23.134 tid:19 December 11, 2016 15:29:23.139 T ID:25 December 11, 2016 15:29:23.146 tid:37 December 11, 2016 15:29:23.152 tid:39 December 11, 2016 15:29:23.158 tid:32 December 11, 2016 15:2 9:23.164 tid:33 December 11, 2016 15:29:23.170 tid:31 December 11, 2016 15:29:23.176 tid:35 December 11, 2016 15:29:23.182 tid:40 2016 1 February 11 15:29:23.189 Tid:15 December 11, 2016 15:29:23.194 tid:18 December 11, 2016 15:29:23.202 tid:17 December 11, 2016 15:29:23.208 tid:10 December 11, 2016 15:29:23 .215 tid:16 December 11, 2016 15:29:23.221
Read-write locks are used in complex multi-threaded environments, and all logs are successfully written to log files, which can be seen by ThreadID and DateTime as being written synchronously by different threads.
The above is the entire content of this article, I hope the content of this article for everyone's study or work can bring some help, but also hope that a lot of support cloud Habitat community!