Отмена (p) потока в критическом разделе

У меня есть приложение, которое запускает несколько потоков, которые иногда отменяются. Эти потоки могут вызывать другой объект, который внутренне обращается к ресурсам (сокету). Чтобы предотвратить одновременный доступ к ресурсу, есть критическая секция, чтобы получить порядок выполнения.

Теперь, при отмене потока, (иногда) случается, что поток находится именно в том коде, который заблокирован критической секцией. Критическая секция заблокирована с помощью объекта, и я надеялся, что после отмены потока этот объект будет разрушен и, следовательно, снимет блокировку. Однако, похоже, это не так, поэтому при уничтожении потока этот объект ресурса постоянно блокируется.

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

Я экспериментировал с предотвращением отмены потока с помощью pthread_setcancelstate, когда раздел заблокирован /разблокирован, однако это выглядит немного грязно и не будет окончательным решением для других ситуаций (например, перехваченных мьютексов и т.д.)

Я знаю, что предпочтительным решением было бы не использовать pthread_cancel, а вместо этого установить флаг в потоке, и он отменит себя, когда будет готов (чистым способом). Однако, поскольку я хочу отменить тему как можно скорее, мне стало интересно (также из академического интереса), будут ли другие варианты сделать это.

4 голоса | спросил Steven 20 MarpmFri, 20 Mar 2009 20:22:34 +03002009-03-20T20:22:34+03:0008 2009, 20:22:34

4 ответа


0

Отмена темы без помощи приложения (упомянутый флаг) - плохая идея. Просто google .

На самом деле отмена настолько сложна, что она была опущена в последней версии C ++ 0x. Вы можете искать http://www.open. -std.org/jtc1/sc22/wg21/docs/papers/2008/n2497.html и вообще не найдете упоминаний об отмене. Вот определение предлагаемого класса потока (там вы не найдете отмены):

class thread
{
public:
    // types:
    class id;
    typedef implementation-defined native_handle_type; // See [thread.native]

    // construct/copy/destroy:
    thread();
    template <class F> explicit thread(F f);
    template <class F, class ...Args> thread(F&& f, Args&&... args);
    ~thread();
    thread(const thread&) = delete;
    thread(thread&&);
    thread& operator=(const thread&) = delete;
    thread& operator=(thread&&);

    // members:
    void swap(thread&&);
    bool joinable() const;
    void join();
    void detach();
    id get_id() const;
    native_handle_type native_handle(); // See [thread.native]

    // static members:
    static unsigned hardware_concurrency();
};
ответил lothar 30 AMpThu, 30 Apr 2009 04:11:12 +040011Thursday 2009, 04:11:12
0

Вы можете использовать pthread_cleanup_push (), чтобы поместить обработчик очистки отмены в стек очистки отмены потоков. Этот обработчик будет отвечать за разблокировку критической секции.

После того, как вы покинете критическую секцию, вы должны вызвать pthread_cleanup_pop (0), чтобы удалить ее.

то есть.

CRIITICAL_SECTION g_section;

void clean_crit_sec( void * )
{
    LeaveCriticalSection( &g_section )
}

void *thrfunc( void * )
{
    EnterCriticalSection( &g_section );
    pthread_cleanup_push( clean_crit_sec, NULL );

    // Do something that may be cancellable

    LeaveCriticalSection( &g_section );
    pthread_cleanup_pop( 0 );
}

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

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

CRIITICAL_SECTION g_section;

void clean_crit_sec( void * )
{
    LeaveCriticalSection( &g_section )
}

void *thrfunc( void * )
{
    EnterCriticalSection( &g_section );
    pthread_cleanup_push( clean_crit_sec, NULL );

    // Do something that may be cancellable

    pthread_cleanup_pop( 1 );  // this will pop the handler and execute it.
}
ответил ScaryAardvark 23 FebruaryEurope/MoscowbTue, 23 Feb 2010 14:11:08 +0300000000pmTue, 23 Feb 2010 14:11:08 +030010 2010, 14:11:08
0

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

Я думаю, что ваше лучшее решение состоит в том, чтобы и использовать флаг и функциональность pthread_cancel. Когда вы вводите сторонний компонент, отключите обработку отмены (PTHREAD_CANCEL_DISABLE); когда вы вернетесь из него, включите его снова. После повторного включения проверьте флаг:

/* In thread which you want to be able to be canceled: */
int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
... call 3rd party component ...
pthread setcancelstate(oldstate, NULL);
if (cancelled_flag) pthread_exit(PTHREAD_CANCELED);

/* In the thread canceling the other one. Note the order of operations
   to avoid race condition: */
cancelled_flag = true;
pthread_cancel(thread_id);
ответил Antti Huima 20 MarpmFri, 20 Mar 2009 21:01:41 +03002009-03-20T21:01:41+03:0009 2009, 21:01:41
0

Идея прерывания потоков без использования четко определенного метода управления (например, флагов) настолько зла, что вам просто не следует этого делать.

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

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

Конечно, разумный дизайн для ваших резьбовых модулей был бы еще лучше ...

(Лично я предпочитаю вообще не использовать потоки и всегда использовать процессы или неблокирующие конструкции)

ответил Arafangion 7 Maypm09 2009, 15:43:51

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132