Несколько потоков, обращающихся к одноэлементному объекту в VS2010 - PullRequest
0 голосов
/ 18 августа 2010

Я использую Visual Studio 2010 для написания простого приложения с графическим интерфейсом на C # /. NET, где я использую класс Logger для записи информации трассировки / отладки в один файл из всех различных классов проекта.(См. Исходный код ниже.)

Конструктор каждого класса записывает запись в журнал, когда создается один из его типов объектов.Одним из этих классов является пользовательский компонент контроллера графического интерфейса (класс FileAttributesCtl), который содержится в нескольких формах графического интерфейса, используемых программой.

Проблема, с которой я столкнулся, состоит в том, что созданы два файла журнала.около 200 мсек.Первый файл журнала содержит (только) сообщение о том, что был создан объект FileAttributesCtl, а второй содержит все другие сообщения, записанные в (предположительно) выходной поток общего файла журнала.Поэтому каждый раз, когда я выполняю свой код проекта, я получаю два файла журнала.

И все же, каждый раз, когда я перестраиваю свой проект (F6), создается файл журнала для объекта FileAttributesCtl, указывающий, что объект управленияэтот тип на самом деле создается в процессе сборки .

Очевидно, это связано с многопоточностью.Если файл журнала не имеет уникального имени (то есть, если я не добавляю уникальную строку даты / времени к имени файла), я получаю исключение, указывающее, что более одного процесса (который фактически является самим процессом VS2010) в настоящее время используетфайл.

Итак, мой вопрос: как мне сделать одноэлементный объект фактически единым объектом?

Вторичный вопрос: почему VS2010 действует таким образом?

//----------------------------------------
// Logger.cs
class Logger
{
    // Singleton object
    private static Logger   s_logger =
        new Logger("C:/Temp/foo.log");

    public static Logger Log
    {
        get { return s_logger; }
    }

    private TextWriter  m_out;

    private Logger(string fname)
    {
        // Add a date/time suffix to the filename
        fname = ...;

        // Open/create the logging output file
        m_out = new StreamWriter(
            new FileStream(fname, FileMode.Create, FileAccess.Write,
                FileShare.Read));
        m_out.WriteLine(DateTime.Now.ToString(
            "'$ 'yyyy-MM-dd' 'HH:mm:ss.fff"));
    }

    ...
}

//----------------------------------------
// FileAttributesCtl.cs
public partial class FileAttributesCtl: UserControl
{
    private Logger  m_log = Logger.Log;

    public FileAttributesCtl()
    {
        m_log.WriteLine("FileAttributesCtl()");  //Written to first logfile
        InitializeComponent();
    }

    ...
}

//----------------------------------------
// FileCopyForm.cs
public partial class FileCopyForm: Form
{
    private Logger  m_log = Logger.Log;

    public FileCopyForm()
    {
        // Setup
        m_log.WriteLine("FileCopyForm()");       //Written to second logfile

        // Initialize the GUI form
        m_log.WriteLine("FileCopyGui.InitializeComponent()");
        InitializeComponent();
        ...
    }

    ...
}

Примечание: Это очень похоже на вопрос декабря 2009 года: Доступ к одноэлементному объекту из другого потока но у него нет ответов на мой вопрос.

Обновление

Дальнейшие исследования показывают, что VS2010 действительно создает экземпляр пользовательского компонента во время сборки, возможно, так, что онможет отобразить его в окне Designer.

Кроме того, действительно есть два отдельных потока, вызывающих конструктор Logger (каждый из которых имеет свой ManagedThreadID).

Использование инициализатора статического класса дляпостроить одиночный объект не работает;Я все еще получаю два файла журнала.

Разрешение

При ближайшем рассмотрении я замечаю, что пользовательский элемент управления создается дважды, и это показано в обоих файлах журнала.

Поэтому я думаю, что проблема полностью в том, что VS создает экземпляр пользовательского объекта управления до выполнения программы , что приводит к созданию первого файла журнала.Затем создается второй файл журнала после того, как программа начинает нормальное выполнение .

Таким образом, первый файл журнала является просто побочным эффектом процесса сборки и на самом деле не имеет ничего общего с несколькими потоками.выполнение во время нормальной работы программы.

Очевидное решение состоит в удалении всего кода побочного эффекта файла журнала из конструкторов компонентов.Или просто полностью игнорируйте первый лог-файл.

Ответы [ 2 ]

1 голос
/ 18 августа 2010

Статические данные + темы = проблемы

Вам необходимо синхронизировать доступ к синглтону (и инициализацию синглтона).

Статический конструктор может помочь

class Logger
{
    private static Logger
    static Logger()
    {
        s_logger = new Logger("C:/Temp/foo.log");
    }

    // ...

или, что еще лучше, используйте библиотеку журналов ( log4net ), которая обрабатывает все это за вас.

Что касается сборок VS, вызывающих создание журнала, я не удивлен. Вероятно, это создание экземпляров форм для обнаружения информации о ваших формах с помощью рефлексии.

обновление по комментариям

@ LoadMaster "Инициализатор статического класса не Работа. Я добавил больше информации в лог-файл вывод для включения текущего потока ManagedThreadID, и, конечно же, есть два разных идентификатора потока создание двух лог-файлов. "

Странно. За MSDN

Статический конструктор для класса выполняет самое большее один раз в данном домен приложения . Исполнение Статический конструктор запускается произойдет первое из следующих событий в домене приложения:

  • Экземпляр класса создан.
  • Любой из статических членов класса ссылки.

В вашей ветке должны быть перемещены домены приложений или в ваших фрагментах отсутствует код.

1 голос
/ 18 августа 2010

Вполне может быть, что Visual Studio строит ваш компонент пользовательского интерфейса (для отображения в конструкторе), и в процессе вызывается ваш конструктор, поэтому вы видите этот файл журнала во время процесса сборки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...