LINUX.ORG.RU

Управление потоками с использованием pthread

 ,


1

2

Всем привет, я использую QT Creator в качестве иде и вот исходники проекта:

про файл:

TEMPLATE = app
CONFIG += console
CONFIG -= qt
LIBS += -lpthread

SOURCES += main.cpp

мейн файл:

#include <iostream>
#include <pthread.h>

int d=0;

using namespace std;

void* task1(void* X)
{
    int OldState, OldType;

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &OldState);
        pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &OldType);

    for(int Count=1; Count<100; Count++)
    {
        d++;
        cout << "В потоке А: " << Count << '\n';
    }
    pthread_testcancel();
}

int main()
{
    pthread_t Threads;
    void* Status;

    pthread_create(&(Threads), NULL, task1, NULL);

    pthread_cancel(Threads);

        pthread_join(Threads, &Status);
        if(Status==PTHREAD_CANCELED)
        {
            cout << "Поток " << " аннулирован" << endl;
        }
        else
        {
            cout << "Поток " << " продолжает выполнение" << endl;
        }
    cout << "d: " << d << endl;
    return 0;
}
проблема вот в чём: при вызове pthread_cancel(Threads); вывод программы такой: В потоке А: 1. И всё, больше ничего, если закомментить этот вызов то всё работает как и задумано(цикл производит 99 итераций), подскажите пожалуйста в чём тут может быть проблема.


Внезапно,да

NAME
     pthread_cancel -- cancel execution	of a thread

LIBRARY
     POSIX Threads Library (libpthread,	-lpthread)

SYNOPSIS
     #include <pthread.h>

     int
     pthread_cancel(pthread_t thread);

DESCRIPTION
     The pthread_cancel() function requests that thread	be canceled.  The tar-
     get thread's cancelability	state and type determines when the cancella-
     tion takes	effect.	 When the cancellation is acted	on, the	cancellation
     cleanup handlers for thread are called.  When the last cancellation
     cleanup handler returns, the thread-specific data destructor functions
     will be called for	thread.	 When the last destructor function returns,
     thread will be terminated.

     The cancellation processing in the	target thread runs asynchronously with
     respect to	the calling thread returning from pthread_cancel().

     A status of PTHREAD_CANCELED is made available to any threads joining
     with the target.  The symbolic constant PTHREAD_CANCELED expands to a
     constant expression of type (void *), whose value matches no pointer to
     an	object in memory nor the value NULL.

RETURN VALUES
     If	successful, the	pthread_cancel() functions will	return zero.  Other-
     wise an error number will be returned to indicate the error.

ERRORS
     The pthread_cancel() function will	fail if:

     [ESRCH]		No thread could	be found corresponding to that speci-
			fied by	the given thread ID.

SEE ALSO
     pthread_cleanup_pop(3), pthread_cleanup_push(3), pthread_exit(3),
     pthread_join(3), pthread_setcancelstate(3), pthread_setcanceltype(3),
     pthread_testcancel(3)

STANDARDS
     The pthread_cancel() function conforms to ISO/IEC 9945-1:1996
     (``POSIX.1'').

AUTHORS
     This manual page was written by David Leonard <d@openbsd.org> for the
     OpenBSD implementation of pthread_cancel().
avc_fan ()

Лучше скажи, чего ты вообще хочешь

avc_fan ()

мейн файл:

* * *
Таких словей
Не найти в словаре
Даже за сто рублей!

nanoolinux ★★★★ ()
Последнее исправление: nanoolinux (всего исправлений: 1)
Ответ на: комментарий от avc_fan

я хочу чтоб функция завершилась на вызове testcancel, а не внутри цикла

Onito ()
Ответ на: комментарий от nanoolinux

спасибо, мне от твоего ненужного комментария легче стало

Onito ()
Ответ на: комментарий от avc_fan

кстати, проблема пропадает если закомментить cout'ы, конечно при системных вызовах генерируется точка аннулирования потока, но, так получается что cout производит системный вывод, что очевидно, ведь это доступ к устройствам ввода/вывода, но как-то это странно...

Onito ()
Ответ на: комментарий от Onito

Это не при чём. Вообще я на фре запустил и всё работает. А проблема стабильно повторяется?

avc_fan ()
Ответ на: комментарий от avc_fan

ну с работающими cout'ами стабильно, тоесть 100% запусков программы приводили к ошибочным результатам, а с закомменчеными всё впорядке, вот уже десяток раз запустил и всё нормально. у меня дебиан 7.4, gcc последний, не помню как он там.

Onito ()
Ответ на: комментарий от Onito

Хмм, лучше послушаем других спецов. У меня шланг 3.3 и gcc 4.2 всё хорошо компилируют.

avc_fan ()
Ответ на: комментарий от avc_fan

проблема теперь в другом: вот другой вариант проги с 3 потоками:

#include <iostream>
#include <pthread.h>

int d=0;

using namespace std;

void* task1(void* X)
{
    int OldState;

    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &OldState);

    for(int Count=1; Count<100; Count++)
    {
        d++;
        //cout << "В потоке А: " << Count << '\n';
    }
}

void* task2(void* X)
{
    int OldState, OldType;

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &OldState);
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &OldType);

    for(int Count=1; Count<100; Count++)
    {
        d++;
        //cout << "В потоке B: " << Count << '\n';
    }
}

void* task3(void* X)
{
    int OldState, OldType;

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &OldState);
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &OldType);

    for(int Count=1; Count<101; Count++)
    {
        d++;
         //cout << "В потоке C: " << Count << endl;
        if((Count%100)==0)
        {
            pthread_testcancel();
        }
    }
}

int main()
{
    pthread_t Threads[3];
    void* Status;

    pthread_create(&(Threads[0]), NULL, task1, NULL);
    pthread_create(&(Threads[1]), NULL, task2, NULL);
    pthread_create(&(Threads[2]), NULL, task3, NULL);

    pthread_cancel(Threads[0]);
    pthread_cancel(Threads[1]);
    pthread_cancel(Threads[2]);


    for(int Count=0; Count<3; Count++)
    {
        pthread_join(Threads[Count], &Status);
        if(Status==PTHREAD_CANCELED)
        {
            cout << "Поток " << Count << " аннулирован" << endl;
        }
        else
        {
            cout << "Поток " << Count << " продолжает выполнение" << endl;
        }
    }
    cout << "d: " << d << endl;
    return 0;
}

Onito ()
Ответ на: комментарий от avc_fan

в этой проге с 3 потоками если многократно запускать прогу результат будет в большинстве случаев 298 но в некоторых 199, тоесть это от планирования потоков такая нестабильность как это контролировать?

Onito ()
Ответ на: комментарий от Onito

а нет, всё я понял, просто завершение 2 потока происходит быстрее чем он отработает, за счёт планирования потоков, всё, теперь вопросов больше нет:) кроме того почему cout'ы ломают всё

Onito ()
Ответ на: комментарий от Onito

Знал бы - рассказал. Сначала хотел вас в маны носом потыкать, но после прочтения понял, что и сам ответа толком не знаю.

Жду, когда кто-нибудь даст правильный ответ.

trex6 ★★★★★ ()
Ответ на: комментарий от Onito

А раз у тебя дебиан, попробуй другие цомпиляторы, а лучше обнови (если можно) libc/pthreads. Может это их вина?

avc_fan ()
Ответ на: комментарий от avc_fan

подскажите как из терминала обновить библиотеку, не делал этого никогда прост :) а так я сомневаюсь что оно поможет так как из учебника откуда взят пример там gcc юзался а учебник явно не новый так что врятли дело в версии pthreads

Onito ()

А чем не устраивает классика?

// worker
while (running) {
  do_smth();
}

// main
running = false;
worker.join();

Reset ★★★★★ ()
Ответ на: комментарий от Onito

apt-get update && apt-get install package_name

package_name может быть уже установлен, тогда обновит

apt-cache search поможет найти нужное

avc_fan ()
Ответ на: комментарий от Onito

Может тут в библиотеках дело? А может мы чего не знаем

avc_fan ()
Ответ на: комментарий от Onito

лучше объясните что не так с cout'ами :)

ввод-вывод ОЧЕНЬ медленный по сравнению со всем остальным. Пока оно пишет в cout хотя бы первую строчку, его уже успевают прибить.

arkhnchul ★★ ()

Это абсолютно нормальное поведение, определённое в POSIX (см. ниже фразы Cancellation points).

cancellation - не является нормальным завершением потока. Нормальное надо реализовывать самому каким-нибудь volatile флагом. pthread_testcancel() добавляет искусственную точку отмены для каких-нибудь числодробительных циклов без системных вызовов.

xaizek ★★★★★ ()
Ответ на: комментарий от Onito

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

arkhnchul ★★ ()
Ответ на: комментарий от avc_fan

ну вот по запросу apt-cache search pthreads выдаёт такое: lib32cr0 - (32bit) Libraries to Checkpoint and Restart Linux processes libcr-dbg - Libraries to Checkpoint and Restart Linux processes libcr-dev - Development files for BLCR libcr0 - Libraries to Checkpoint and Restart Linux processes libilmbase6 - several utility libraries from ILM used by OpenEXR libevent-pthreads-2.0-5 - Asynchronous event notification library (pthreads) libpthread-stubs0 - pthread stubs not provided by native libc libpthread-stubs0-dev - pthread stubs not provided by native libc, development files pbzip2 - parallel bzip2 implementation libzthread-2.3-2 - Object-oriented synchronization library for C++ libzthread-dev - Object-oriented synchronization library for C++ blcr-testsuite - пользовательские утилиты для сохранения и восстановления состояния процессов в Linux blcr-util - инструменты пространства пользователя для контроля за состоянием и перезапуска процессов в Linux

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

Onito ()
Ответ на: комментарий от arkhnchul

ну даже если cout очень медленный это ничего не меняет так как точка выхода генерируется после цикла когда уже cout нет, а на счёт пустых циклов тоже нестыковка, во первых там происходит приращение переменной d а во вторых врятли компилятор cout считает делом а приращение переменной пустым циклом :)

Onito ()
Ответ на: комментарий от Onito

Странно даже, что просто «pthread» или «pthread-dev» нет. Наверное, ещё в каком-нибудь пакете. Я уже давно не пользуюсь демьяном

avc_fan ()
Ответ на: комментарий от xaizek

так даже если оно не является нормальным это не отменяет проблему что с закоменченными cout'ами всё работает

Onito ()
Ответ на: комментарий от xaizek

А не пояснишь это:

POSIX.1 specifies that certain functions must, and certain other
       functions may, be cancellation points.  If a thread is cancelable,
       its cancelability type is deferred, and a cancellation request is
       pending for the thread, then the thread is canceled when it calls a
       function that is a cancellation point.

То есть, как я понял, в случае если тред отменяемый и тип откладываемый (т.е. как у ТС'а), то тред завершается при вызове функции-точки-отмены, а у ТС'а это task1? Получается, действительно, какое-то неверное использование, если я понял правильно

avc_fan ()
Ответ на: комментарий от xaizek

и кстати Вы ведь сами только что назвали нормальную причину использовать testcancel, внутри потоков где нет системных вызовов, это ведь нормально скажем если у меня вычисления дублируются на двух машинах и если на одной они завершились быстрее то на второй их можно прервать, и в таком случае только с помощью testcancel, да и например сценарий командной оболочки когда существует множество разнородных потоков и возможны форс-мажорные ситуации когда нужно кильнуть поток а он там чёто своё считает, например форматирует XML из одного представления в другое а вы закрываете приложение естесно через основной поток и нужно всех сыночков быстро кильнуть и тогда только опять testcancel вам в помощь

Onito ()
Ответ на: комментарий от avc_fan

у task1 отключено аннулирование, и запрос на завершение просто игнорируется, вся проблема в task3, где он какраз отложенный, если хочешь можешь проверить это просто закомментив создание 1 потока и вызов cancel

Onito ()
Ответ на: комментарий от Onito

проблема в task3 потому что если я комменчу создание 3 поткоа и вызов cancel для него то всё работает и с cout'ами

Onito ()
Ответ на: комментарий от avc_fan

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

Onito ()
Ответ на: комментарий от avc_fan

и попробуй плиз запустить №2 пример раз у тебя первый заработал интересно заработает ли второй, мб просто мне не повезло

Onito ()
Ответ на: комментарий от Onito

на счёт пустых циклов тоже нестыковка, во первых там происходит приращение переменной d а во вторых врятли компилятор cout считает делом а приращение переменной пустым циклом :)

вот как раз cout (I/O) - дело для компилятора, ибо он не может вообще определить, что с его выводом делается. А приращение переменной - внезапно, компилятор вполне прослеживает, что с ней дальше будет происходить. В жабе ворнинги типа «variable valued, but was not accessed» (в том смысле, что значение переменной присвоено, но нигде далее не используется) вполне распространенное явление, и таковые переменные жаба из рантайма выкидывает. Не думаю, что gcc тупее javac.

arkhnchul ★★ ()
Последнее исправление: arkhnchul (всего исправлений: 1)
Ответ на: комментарий от arkhnchul

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

Onito ()
Ответ на: комментарий от Onito
Поток 0 продолжает выполнение
Поток 1 продолжает выполнение
Поток 2 аннулирован
d: 298
avc_fan ()
Ответ на: комментарий от avc_fan

здорово! а убери комменты с cout'ов в taskX, а то у меня так тоже работает :)

Onito ()

xaizek уже ответил. Поведение абсолютно нормальное. Любой ввод/вывод это cancellation point. Это значит что pthread_testcancel() будет вызван не только за циклом, но и при каждом вызове внутри cout.

Посмотри http://www.lektorium.tv/lecture/15293 поможет. И еще список точек остановки гуглиться здесь http://stackoverflow.com/a/434139

bumbaram ()
Ответ на: комментарий от trex6

Кстати, в C++11 cout не сделали потокобезопасным? Т.е. вроде для доступа к нему mutex'ы не нужны же.

deterok ★★★★★ ()
Ответ на: комментарий от deterok

Этот комментарий относился ко второмц пртмеру ТС, там ввода-вывода нет в потоках, только приращение переменной.

trex6 ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.