2012-02-22 2 views
1

У меня есть служба Windows, которая контролирует папку для создания новых файлов. Когда файл будет добавлен в папку, служба отправит файл для обработки второму приложению. 2-е приложение фактически является консольным приложением, но установлено как «Приложение Windows», чтобы избежать создания окна консоли. Служба и второе приложение работают на сервере. Для реализации только один файл, чтобы обработать каждый раз, семафор был реализован в 2-приложение, например, так:Как обрабатывать события закрытия приложений с помощью C#

public class Program 
{ 
    static Semaphore semaphore; 
    [STAThread] 
    static void Main(string[] args) 
    { 
     StartupConfigurator startConfig = new StartupConfigurator(); 
     semaphore = new Semaphore(1, 1, "2ndApp"); 
     semaphore.WaitOne(); 
     startConfig.StartProcessCommandLine(args); 
     semaphore.Release(1); 
     Environment.Exit(1); 
    } 
} 

Это прекрасно работает до тех пор, как Applicatin выходит изящно и семафор освобождается. Во втором приложении есть строка кода, которая во время выполнения просто зависает (в основном пытается войти на сервер, но не удается, причины не доступны для 2-го приложения), он просто висит там. Из-за способа написания службы он запускает новый экземпляр 2-го приложения каждый раз, когда создается новый файл. Это может быть добавление нового файла или добавление сразу нескольких файлов в просматриваемую папку. Например, если 4 файла отбрасываются в просматриваемую папку, служба запустит 4 экземпляра второго приложения. Второе приложение завершает файл, семафор освобождается и обрабатывается следующий файл. Это прекрасно работает, если он делает это, т. Е. Выходит изящно. В случае, когда он зависает, единственным способом возобновить обработку является закрытие всех экземпляров из Диспетчера задач, завершение только проблемного экземпляра тоже не поможет, все они должны быть завершены.

Было обсуждение по теме here, но я не знаю, как ее использовать. Есть ли способ, чтобы второе приложение узнало, что оно было принудительно закончено, и семафор можно освободить.

С уважением.

+0

Я полагаю, вы должны предотвратить наложение 2-го приложения ... Положите тайм-аут вокруг операции подвешивания. – zmbq

+0

Сначала добавьте попытку/наконец, чтобы убедиться, что семафор выпущен, если выбрано исключение (это не поможет, если вы его убьете, это просто хорошая идея). Во-вторых, вы не можете сделать время входа в систему, а не вешать бесконечно? – Sven

ответ

0

Есть ли способ, чтобы 2-е приложение узнало, что оно было принудительно закончено, и семафор можно отпустить.

Нет, когда процесс убит, нет возможности очистить, выполнить окончательные блоки и т. Д. См. this. Лучше всего запустить операцию зависания в отдельном потоке и вызвать соединение в потоке, чтобы дождаться завершения операции. Образец:

bool completed = false; 
try 
{ 
    Thread thread = new Thread(() => startConfig.StartProcessCommmandLine(args)); 
    thread.IsBackground = true; 
    thread.Start(); 
    bool completed = thread.Join(60000); // 60s timeout 
} 
finally 
{ 
    semaphore.Release(1); 
} 
Environment.Exit(completed ? 0 : 1); 

Как правило, код выхода 0 считается нормальным. Метод try/catch важен, потому что, если ваш поток генерирует необработанное исключение, мы хотим, чтобы он освободил семафор до того, как процесс был сбит.

+0

Привет, Майк, логин для сервера не является потокобезопасным.Я думаю об упаковке линии входа вокруг таймаута и выхода из метода, если он превышает это. Любые другие идеи! – Codehelp

+0

Что вы подразумеваете под «login to server is not thread safe»? вышеупомянутые вызовы StartProcessCommandLine (при условии, что это делает логин) только на одном потоке. если startConfig нельзя построить на одном потоке и использовать в другом, то положите все на другой поток. Я не уверен, как вы планируете «обернуть линию входа в очередь от тайм-аута» без другого потока, если для операции входа нет определенного параметра таймаута. –

+0

Привет Майк, вызов StartProcessCommandLine не выполняет вход в систему, он только запускает процесс, который состоит из нескольких шагов, одним из которых является Login. Теперь метод Login является частью сторонней библиотеки, которая, к сожалению, не дает таймаута, когда что-то идет не так. «Что-то» здесь - это то, на что я не могу контролировать. Итак, я продолжу предлагать ввести логин в новый поток, а затем выйти из него. Спасибо за указание в правильном направлении. – Codehelp

0

Если второе приложение запускается службой, я бы поместил код, который синхронизирует обработку в службе.

Служба узнает, запущено ли приложение для обработки, и когда оно будет завершено, оно запустит другое. Само приложение может иметь только простую проверку, если другое приложение уже запущено (с помощью семафора или мьютекса) и выйдите, если оно есть.

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

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