Корректно заключительное приложение многопоточности?

Держите 2 стека, назовем их inbox и outbox.

Поставить в очередь :

  • Вставить новый элемент в очередь inbox

:

  • Если outbox пусто, заполните его, вытолкнув каждый элемент из inbox и вставив его в outbox

  • Pop и вернув верхний элемент из outbox

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

Вот реализация в Java:

public class Queue<E>
{

    private Stack<E> inbox = new Stack<E>();
    private Stack<E> outbox = new Stack<E>();

    public void queue(E item) {
        inbox.push(item);
    }

    public E dequeue() {
        if (outbox.isEmpty()) {
            while (!inbox.isEmpty()) {
               outbox.push(inbox.pop());
            }
        }
        return outbox.pop();
    }

}
5
задан Ahmed Said 28 June 2009 в 14:36
поделиться

3 ответа

Предполагая " Вы сказали: вы не используете транзакции из соображений производительности, а вместо этого используете мьютексы. Это НЕПРАВИЛЬНО на многих уровнях. Во-первых, транзакции могут выполнять определенные операции быстрее, например, попробуйте вставить 10 строк в таблицу, попробуйте еще раз в транзакции, версия транзакции будет быстрее. Во-вторых, что произойдет, когда / если ваше приложение выйдет из строя, вы повредите свою БД? Что происходит, когда выполняется несколько экземпляров вашего приложения? Или пока вы запускаете отчеты по своей БД в анализаторе запросов?

6
ответ дан 18 December 2019 в 09:52
поделиться

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

Я показал подходящую очередь производителя / потребителя здесь - рабочий будет просто быть:

void WriterLoop() {
    SomeWorkItem item; // could be a `DataTable` or similar
    while(queue.TryDequeue(out item)) {
        // process item
    }
    // queue is empty and has been closed; all done, so exit...
}

Вот полный пример, основанный на SizeQueue <> - обратите внимание, что процесс не завершается до тех пор, пока читатель и писатель полностью не завершат работу. Если вы не хотите опустошать очередь (т.е. вы хотите выйти раньше и забыть обо всех незавершенных работах), тогда хорошо - добавьте где-нибудь дополнительный (изменчивый) флаг.

static class Program {
    static void Write(object message) {
        Console.WriteLine(Thread.CurrentThread.Name + ": " + message);
    }
    static void Main() {
        Thread.CurrentThread.Name = "Reader";
        Thread writer = new Thread(WriterLoop);
        writer.Name = "Writer";
        var queue = new SizeQueue<int>(100);
        writer.Start(queue);
        // reader loop - note this can run parallel
        // to the writer
        for (int i = 0; i < 100; i++) {
            if (i % 10 == 9) Write(i);
            queue.Enqueue(i);
            Thread.Sleep(5); // pretend it takes time
        }
        queue.Close();
        Write("exiting");
    }
    static void WriterLoop(object state) {
        var queue = (SizeQueue<int>)state;
        int i;
        while (queue.TryDequeue(out i)) {
            if(i%10==9) Write(i);
            Thread.Sleep(10); // pretend it takes time
        }
        Write("exiting");
    }
}
8
ответ дан 18 December 2019 в 09:52
поделиться

Ваше ожидание мьютекса должно включать тайм-аут. Внешний цикл каждого потока может проверять наличие флага «пожалуйста, закройте сейчас». Чтобы завершить работу, установите флаг «Пожалуйста, закройте сейчас» для каждого потока, затем используйте «join», чтобы дождаться завершения каждого потока.

3
ответ дан 18 December 2019 в 09:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: