Использование многопоточности и критических разделов - C ++ - PullRequest
3 голосов
/ 14 декабря 2010

Меня немного смущает правильное использование критических секций в многопоточных приложениях. В моем приложении есть несколько объектов (некоторые циклические буферы и объект последовательного порта), которые совместно используются потоками. Должен ли доступ к этим объектам всегда располагаться в критических секциях или только в определенное время? Я подозреваю только в определенные моменты, потому что, когда я пытался обернуть каждое использование EnterCriticalSection / LeaveCriticalSection, я столкнулся с тем, что казалось тупиковым условием. Любое понимание, которое вы можете иметь, будет оценено. Спасибо.

Ответы [ 2 ]

6 голосов
/ 14 декабря 2010

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

Трудно дать какой-либо совет, не зная больше о вашем коде, но здесьВот некоторые общие моменты, о которых следует помнить.

1) Критические разделы защищают ресурсы , а не процессы .

2) Введите / оставьте критические секции в одном и том же порядке во всех потоках.Если поток A входит в Foo, затем входит в Bar, тогда поток B должен вводить Foo и Bar в том же порядке.Если вы этого не сделаете, вы можете создать расу.

3) Вход и выход должны быть выполнены в обратном порядке.Например, поскольку вы вошли в Foo, а затем в Bar, вы должны покинуть Bar, прежде чем покинуть Foo.Если вы этого не сделаете, вы можете создать тупик.

4) Сохраняйте блокировки в течение минимально возможного периода времени.Если вы покончили с Foo до того, как начали использовать Bar, отпустите Foo перед тем, как взять Bar.Но вы все равно должны помнить правила заказа сверху.В каждом потоке, который использует Foo и Bar, вы должны приобретать и выпускать в одном и том же порядке:

  Enter Foo
  Use Foo
  Leave Foo
  Enter Bar
  Use Bar
  Leave Bar

5) Если вы читаете только 99,9% времени и пишете 0,1% времени, не делайтестараться быть умнымВы все еще должны ввести критическую секунду, даже когда вы только читаете.Это потому, что вы не хотите, чтобы запись начиналась, когда вы находитесь в середине чтения.

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

2 голосов
/ 14 декабря 2010

Используйте оболочку C ++ вокруг критической секции, которая поддерживает RAII:

{
    CriticalSectionLock lock ( mutex_ );

    Do stuff...
}

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

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

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

С портом ввода-вывода подумайте, нужно ли вам блокировать выход одновременно с вводом - часто возникает ситуация, когда что-то пытаетсяписать, потом ожидает читать, или наоборот.Если у вас есть две блокировки, то вы можете получить взаимоблокировку, если один поток пишет, затем читает, а другой читает, а затем пишет.Часто наличие одного потока, который выполняет IO и очередь запросов, решает эту проблему, но это немного сложнее, чем просто обзвонить вызовы блокировками, и без более подробной информации я не могу это порекомендовать.

...