C # Threading с событиями ручного сброса - PullRequest
2 голосов
/ 17 июля 2011

У меня есть приложение, которое импортирует данные, прочитанные из текстовых файлов из каталога в базу данных. У меня есть пользовательский интерфейс, который позволяет пользователю нажать кнопку импорта и начать импорт данных, и когда пользователь снова нажимает на эту кнопку, я хотел прекратить импорт данных в этих файлах. Я начал использовать потоки, чтобы разрешить это, чтобы не замораживать пользовательский интерфейс во время импорта данных. Но у меня есть несколько проблем. Я начал использовать thread.Abort () для уничтожения потока после того, как пользователь перестал хотеть импортировать, но когда пользователь снова щелкает по импорту, некоторые дубликаты данных добавляются в базу данных, потому что они начинают читать в верхней части текстового файла, который я не хочу , Мне сказали использовать ManualResetEvents и Thread.Join (), чтобы инициировать завершение импорта, но я запутался, как это должно работать. Прямо сейчас мой код выглядит так:

    public ManualResetEvent event1 = new ManualResetEvent(false);
    public Thread workerThread;


    public Form1
    {
        InitializeComponent();
    }

    private void importButton_Click(object sender, EventArgs e)
    {
        if(importButton.Text == "Begin Import")
        {
            importButton.Text = "Stop Import";
            //runs a service that begins reading and importing data and writing to
            //a "console" box.
            Service service = new Service(consoleBox);
            //run the new thread to begin importing data
            workerThread = new Thread(service.importData);
            workerThread.Start();

        }
        else
        {
            importButton.Text = "Begin Import";
            event1.Set();
            while(!event1.WaitOne(TimeSpan.FromSeconds(4)))
            {    //imports data for 30 more text files 
                  service.importData(30);
                  workerThread.Join();

            }


        }
    }

По сути, я пытаюсь сохранить зацикливание и проверку протектора, чтобы увидеть, есть ли какие-либо файлы, которые нужно прочитать, если есть, затем импортировать данные, иначе они спят в течение 4 секунд. Должен ли я использовать поточный таймер для этого? Я немного не уверен, что делать.

Ответы [ 2 ]

1 голос
/ 17 июля 2011

Ни в коем случае не блокируйте поток пользовательского интерфейса, вызывая Thread.Join или ManualResetEvent.WaitOne.Это сделает именно то, что вы пытались предотвратить;заморозить интерфейс.Вместо этого вам нужно создать MRE с первоначальным состоянием true.Затем в методе importData необходимо периодически вызывать WaitOne, чтобы узнать, следует ли продолжить импорт (когда событие сигнализируется) или сделать паузу (если событие не сигнализировано).

Вот примерный набросоккак бы вы назвали WaitOne внутри importData метода.Очевидно, вам нужно будет внести изменения, чтобы они соответствовали вашей конкретной реализации.

private void importData()
{
  foreach (string filePath in GetFilesInSomeDirectory())
  {
    event1.WaitOne(); // Block when the MRE is unsignaled.
  }
}

Затем из обработчика событий importButton.Click вы можете вызвать event1.Reset, чтобы приостановить операцию импорта, или event1.Set, чтобы возобновить.it.

Кроме того, вы должны стараться избегать звонков Thread.Abort любой ценой.Это обычно приводит к большему количеству проблем, если не принять особые, почти почти невозможные меры, чтобы не повредить состояние AppDomain.

0 голосов
/ 17 июля 2011

Используйте таймер для запуска процесса импорта вместо потока и определите переменную, чтобы проверить, если пользовательский запрос на stopinstead равен thread.Abort(), чего, кстати, следует избегать.

В этом коде используйте System.Timers.Timer. и пометить AutoReset свойство как false, поэтому импортируйте данные только в том случае, если пользователь не запросил остановку.

private System.Timers.Timer _importTimer = new System.Timers.Timer();
private volatile bool _requestStopImport = false;

public Form1()
{
    InitializeComponent();

    _importTimer.Interval = 4000;//4 seconds
    _importTimer.AutoReset = false;//not automatically raise elapse event each time interval elapsed, only if we don't want to stop.
    _importTimer.Elapsed += OnImportTimerElapced;
}

private void importButton_Click(object sender, EventArgs e)
{
    if (importButton.Text == "Begin Import")
    {
        importButton.Text = "Stop Import";
        StartImport();
    }
    else
    {
        importButton.Text = "Begin Import";
        StopImport();
    }
}

private void OnImportTimerElapced(object sender, System.Timers.TimerEventArgs e)
{
    //runs a service that begins reading and importing data and writing to
    //a "console" box.
    Service service = new Service(consoleBox);//or maybe this would be a class level variable
    service.importData();

    if (!_requestStopImport)
    { 
        _importTimer.Start();
    }
}

private void StartImport()
{
    _requestStopImport = false;
    _importTimer.Start();
}

private void StopImport()
{
    _requestStopImport = true;
    _importTimer.Stop();
}

Как вы заметили, вам не нужно использовать ManualResetEvent здесь. однако, если вы хотите получать уведомление о завершении кода или около того, вы можете использовать AutoResetEvent или вызвать событие для более подробного примера, проверьте this .

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