2013-05-03 2 views
0

Когда я отлаживаю эту небольшую программу шаг за шагом с помощью кнопки F10, программа рациональна, пока не достигнет уровня timer.Elapsed +=. после этого предполагается, что позвоните по моему методу Check(MyConn), но это не так! он возвращается к MyConn.Close();, и он отскакивает между этими двумя, затем он внезапно закрывает программу!Методы и таймер в C#

Мне было интересно, откуда эта проблема возникает ... не может быть из этой строки: timer.Elapsed += (timerSender, timerEvent) => timer_Elapsed(timerSender, timerEvent, MyConn);? Это было решение, размещенное на этом форуме в случае, если я хотел бы привести в аргументе MyConn к timer_Elapsed ...

Заранее за вашу помощь!

static void Main(string[] args) 
{ 
    // create connection 
    string ConnStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Users\\mike\\Documents\\Database1.mdb;"; 

    OleDbConnection MyConn = new OleDbConnection(ConnStr); 
    MyConn.Open(); 

    initTimer(MyConn); 

    MyConn.Close(); 
} 

static void initTimer(OleDbConnection MyConn) 
{ 
    //set up a timer 
    Timer timer = new Timer(); 
    timer.Interval = 2000; // check every 2s (2000ms) if the values in the database changed 
    timer.Enabled = true; //enable the timer, so when the timer elapses after 2s, it performs some calculations 

    timer.Elapsed += (timerSender, timerEvent) => timer_Elapsed(timerSender, timerEvent, MyConn); 
} 

static void timer_Elapsed(object sender, ElapsedEventArgs e, OleDbConnection MyConn) 
{ 
    Check(MyConn); // Check is a method I have in my program which takes as argument "MyConn" 
} 
+1

Пара вещей - в чем исключение? и что делает 'Check' с объектом' MyConn'? Поскольку вы немедленно закрываете соединение * до *, у таймера есть шанс его использовать. – James

ответ

2

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

В случае, если ваша программа не прекращается, таймер будет отсчитывать с 2000 года. Когда он достигнет нуля, он запустит событие. Это происходит в другом потоке и происходит параллельно с вашим основным тетом. Вы даже проверите соединение, которое будет закрыто.

Если вы хотите, чтобы главная угроза подождала, пока событие будет запущено, зачем вообще использовать таймер? Почему бы не сделать это?

static void Main(string[] args) 
{ 
    // create connection 
    string ConnStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Users\\mike\\Documents\\Database1.mdb;"; 

    using(OleDbConnection MyConn = new OleDbConnection(ConnStr)) 
    { 
     MyConn.Open(); 
     do 
     { 
      Thread.Sleep(2000); 
      Check(MyConn); 
     } 
     while(someValueToIndicateTheApplicationCanTerminate); 
    } 
} 
+0

Я не знал, что событие было в другом потоке, теперь это имеет смысл, потому что они работают в одно и то же время. Я хочу, чтобы каждый час времени (в моем примере 2сек) выполнялся мой метод «Check (MyConn)». С тем, как вы его написали, вы помещаете «Thread.Sleep (3000)» означает ли это, что вы разрешаете основному потоку спать на 3 секунды? Если это так, я не вижу, как будет запущен метод «Проверить (MyConn)», потому что вы закрыли соединение раньше, не так ли? – Mike

+0

Да. 'Thread.Sleep (3000)' означает ожидание в течение 3 секунд. Я не знал, что проверил ваш 'Check'. Он проверил наличие открытого или закрытого соединения? Или пропустить что-нибудь еще? Конечно, вы можете переместить мой код задержки перед кодом, который закрывает соединение. –

+0

Я обновил свой ответ по вашему запросу. –

3

Это совершенно нормальное поведение.

Код timer.Elapsed += регистрируется только. Через 2 секунды событие будет запущено, но ваш основной поток будет продолжен как обычно и вернется к функции Main(). Затем он вызовет MyConn.Close(), а затем закончит функцию Main().

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

Если это приложение, которое будет «оставаться в живых», как услуга или приложение формы, то к моменту начала события timer_Elapsed соединение будет уже закрыто.


Я хотел бы предложить, если у вас есть «остаться в живых» приложение, то вы должны переместить/Close код Open подключения к функции, которая на самом деле делает их использование. Что в этом случае будет внутри события timer_Elapsed.

Если у вас нет приложения «остаться в живых», вам, вероятно, следует избегать таймеров (и всего, что связано с отдельными потоками).

Кстати, я продолжаю говорить «оставайтесь в живых». Надеюсь, вы знаете, что я имею в виду. Я не знаю более технического термина, чтобы описать его.

+0

На самом деле у меня есть консольное приложение. Спасибо, теперь я понимаю поведение потоков. Но как я могу исправить это, если, например, мне нужен мой метод «Check (MyConn)»; для запуска каждого круга времени (2сек в моем примере), в то время как удерживать поток основного? – Mike

+0

@Mike: вы можете использовать цикл while в вашей функции «Главная», которая спит в течение каждого цикла. Чтобы избежать бесконечности, вам нужно проверить каждый цикл, чтобы увидеть, должен ли он выйти или нет. Как вы устанавливаете этот флаг, хотя и зависит от того, что вы делаете в целом – musefan

+0

Я хочу сделать автоматическую проверку, я хочу, чтобы мой метод Проверял, чтобы работать бесконечно каждые 2 секунды ... Я предполагаю, что это означает, что главное не может закрыть , нет? Я хочу, чтобы основной поток не закрывал коннект, пока событие таймера запускает метод Check ... это то, что я пытаюсь сделать! – Mike

Смежные вопросы