同步线程访问并用C#编写 [英] Synchronizing thread access and write in C#

查看:89
本文介绍了同步线程访问并用C#编写的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用C#编写的多线程端口扫描器应用程序,我想在应用程序运行时将一些内容同时打印到控制台和日志文件中.因此,我有以下帮助程序类,该类可以很好地同时写入日志文件和控制台.

I have a multithreaded port scanner app written in C#, and I want to print some stuff both to the console and a log file as the app runs. For this reason, I have the following helper class, which works fine in writing both to a log file and the console.

public class Output
{
    private const string LOG_DIRECTORY = "Logs";
    private readonly string LogDirPath = Path.Combine(Directory.GetCurrentDirectory(), LOG_DIRECTORY);

    private static Output _outputSingleton;
    private static Output OutputSingleton {
        get {
            if (_outputSingleton == null)
            {
                _outputSingleton = new Output();
            }
            return _outputSingleton;
        }
    }

    public StreamWriter SW { get; set; }

    public Output()
    {
        EnsureLogDirectoryExists();
        InstantiateStreamWriter();
    }

    ~Output()
    {
        if (SW != null)
        {
            try
            {
                SW.Dispose();
            }
            catch (ObjectDisposedException) { } // object already disposed - ignore exception
        }
    }

    public static void WriteLine(string str)
    {
        Console.WriteLine(str);
        OutputSingleton.SW.WriteLine(str);
    }

    public static void Write(string str)
    {
        Console.Write(str);
        OutputSingleton.SW.Write(str);
    }

    private void InstantiateStreamWriter()
    {
        long ticks = DateTime.Now.Ticks;
        string logFilename = "scan_" + ticks.ToString() + ".txt";
        string filePath = Path.Combine(LogDirPath, logFilename);
        try
        {
            SW = new StreamWriter(filePath);
            SW.AutoFlush = true;
        }
        catch (UnauthorizedAccessException ex)
        {
            throw new ApplicationException(string.Format("Access denied. Could not instantiate StreamWriter using path: {0}.", filePath), ex);
        }
    }

    private void EnsureLogDirectoryExists()
    {
        if (!Directory.Exists(LogDirPath))
        {
            try
            {
                Directory.CreateDirectory(LogDirPath);
            }
            catch (UnauthorizedAccessException ex)
            {
                throw new ApplicationException(string.Format("Access denied. Could not create log directory using path: {0}.", LogDirPath), ex);
            }
        }
    }
}

问题是,由于我的应用程序是多线程的,所以有时我会创建多个日志文件,每个日志文件都是部分写入的,有时我会抛出异常,因为一个线程在被另一个线程使用时无法访问同一位置进行写入.有没有办法使我的上述Output类也成为多线程的,这样我就可以避免上述问题?

The problem is that since my app is multithreading sometimes I get multiple log files created, each of them partially written, and sometimes I get exception thrown since one thread cannot access the same place to write while it is being used by another thread. Is there any way to make my above Output class multithreaded too, so that I avoid the above mentioned problems?

推荐答案

使用单个文件和lock策略应该可以完成这项工作:

Using a single file and a lock strategy should do the job:

private Object m_Lock = new Object();

public static void WriteLine(string str)
{
    lock (m_Lock)
    {
        Console.WriteLine(str);
        OutputSingleton.SW.WriteLine(str);
    }
}

public static void Write(string str)
{
    lock (m_Lock)
    {
        Console.Write(str);
        OutputSingleton.SW.Write(str);
    }
}

private void InstantiateStreamWriter()
{
    string logFilename = "Log.txt";
    string filePath = Path.Combine(LogDirPath, logFilename);

    try
    {
        SW = new StreamWriter(filePath);
        SW.AutoFlush = true;
    }
    catch (UnauthorizedAccessException ex)
    {
        throw new ApplicationException(string.Format("Access denied. Could not instantiate StreamWriter using path: {0}.", filePath), ex);
    }
}

这里的问题来自于共享锁.如果对多个方法使用相同的锁,则锁定一个方法也会同时锁定其他方法(在您的情况下为WriteWriteLine).在我看来,这是完全可以的,因为它们是严格相关的...但是,如果频繁调用这些方法,可能会造成瓶颈.另一方面,单独的锁将使方法独立运行,这甚至更糟.

The problem here comes with the shared lock. If you use the same lock on multiple methods, then locking one method locks other methods as well (in your case Write and WriteLine). It looks totally fine to me since they are strictly related... but this may create a bottleneck if the methods are called very frequently. On the other side, separate locks would make the methods run independently and this is even worse.

尝试将两个方法合并为一个,因此您不必担心处理单独方法上的锁:

Try to merge the two methods into one as follows, so you don't have to care about handling locks on separate methods:

public static void WriteLine(String str, Boolean line = true)
{
    lock (m_Lock)
    {
        if (line)
        {
            Console.WriteLine(str);
            OutputSingleton.SW.WriteLine(str);
        }
        else
        {
            Console.Write(str);
            OutputSingleton.SW.Write(str);
        }
    }
}

这篇关于同步线程访问并用C#编写的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆