Russian Qt Forum

Qt => Общие вопросы => Тема начата: melifaro от Июль 28, 2009, 22:46



Название: Синхронизация потоков, один из потоков не верно работает.
Отправлено: melifaro от Июль 28, 2009, 22:46
Следующая ситуация:
Один поток заносит данные в определенную структуру (обращается к ней по указателю), другой обсчитывает и пишет данные в файл.

Код:
void WhriteThread::run()
{
    QLinkedList<int>::const_iterator i = list->begin();
    curr = first;
    while(i!= list->end())
    {
        mutex.lock();
        while(!agree)
            writeCond.wait(&mutex);
        curr->num = *i;
        curr = curr->next;
        agree = 0;
        readCond.wakeAll();
        i++;
        mutex.unlock();
    }
}

Код:
void ReadThread::run()
{
    file.setFileName(fileName);
    file.remove();
    if(!file.open(QIODevice::WriteOnly))
    {
        return;
    }
    QTextStream stream(&file);
    forever
    {
        if(stopped)
        {
            //stopped = false;
            break;
        }
        mutex.lock();
        while(agree)
            readCond.wait(&mutex);

       // math();
        stream << QString::number(curr->prev->num)<<" ";
        agree = 1;
        writeCond.wakeAll();
        mutex.unlock();
    }
    file.close();
}

число элементов в list - 100.000 (собственно узлы хранят числа от 0 до 99.999), когда поток WhriteThread заканчивает свою работу (о чем сообщает сигналом) он посылает сигнал в слот второго потока и значение stopped становится true. Соответственно при этом поток ReadThread должен завершить свою работу и доложить об этом. В реале получается, что поток WhriteThread закончил работу, а ReadThread виснет. При этом, смотря файл всегда на одном и том же числе где-то ~97000. Если менять число элементов, то всё равно не досчитывает. Пробовал использовать семафоры - результат тот же. Я чего-то не понимаю. Подскажите пожалуйста.


Название: Re: Синхронизация потоков, один из потоков не верно работает.
Отправлено: ритт от Июль 28, 2009, 23:53
что такое curr->prev->num? где сигнал?
впечатление, что ты не хочешь получить ответ на свой вопрос...


Название: Re: Синхронизация потоков, один из потоков не верно работает.
Отправлено: melifaro от Июль 29, 2009, 07:27
Код:
 struct.h...
const int MAX = 100000;
struct SuperStruct
{
    int num;
    SuperStruct *next;
    SuperStruct *prev;
};

extern SuperStruct *first;
extern SuperStruct *curr;
extern void createSuperStruct();
...
SuperStruct - циклический список из n элементов.

Код:
dialog.cpp
    ...
    connect(&wThread,SIGNAL(finished()),&rThread,SLOT(stop()));
    connect(&wThread,SIGNAL(finished()),this,SLOT(showMessage()));
    connect(&rThread,SIGNAL(finished()),this,SLOT(showMessage()));

Код:
 dialog.h
...
private:
    ReadThread rThread;
    WhriteThread wThread;


Название: Re: Синхронизация потоков, один из потоков не верно работает.
Отправлено: ритт от Июль 29, 2009, 08:23
советую внимательно почитать док по Wait Conditions Example. подозреваю, что код выше использован как раз из этого примера, но отличия имеются.


Название: Re: Синхронизация потоков, один из потоков не верно работает.
Отправлено: Winstrol от Июль 29, 2009, 09:39
Следующая ситуация:
Один поток заносит данные в определенную структуру (обращается к ней по указателю), другой обсчитывает и пишет данные в файл.

Пользование низкоуровневыми примитивами синхронизации вроде QWaitCondition вам запрещено, примите это как данность. Они нужны для:
  • переписывания готовых алгоритмов(где уже есть wait conditions) на QT
  • опытных пользователей

В большинстве случаев можно без них спокойно обойтись.

По сему, до того как ознакомитесь с
  • http://labs.trolltech.com/blogs/2006/12/04/threading-without-the-headache/
  • материалами Assistant
  • примерами из qt/examples/qtconcurrent и qt/examples/threads
отвечать на поставленный вопрос, без внятного понимания автором, чего он хочет, не вижу смысла.


Название: Re: Синхронизация потоков, один из потоков не верно работает.
Отправлено: melifaro от Июль 29, 2009, 18:50
По-моему ситуацию я описал весьма конкретно. И задача тоже ясна.
Цитировать
Пользование низкоуровневыми примитивами синхронизации вроде QWaitCondition вам запрещено, примите это как данность.
Что тогда посоветуешь использовать?
Похоже "читайте Assistant" самый частый ответ на форуме.


Название: Re: Синхронизация потоков, один из потоков не верно работает.
Отправлено: ритт от Июль 29, 2009, 19:17
Похоже "читайте Assistant" самый частый ответ на форуме.
так и есть.
при желании можно было бы составить статистику, показывающую, что большинство вопросов задаётся от нежелания/неумения читать документацию...

По-моему ситуацию я описал весьма конкретно. И задача тоже ясна.
Что тогда посоветуешь использовать?
опиши задачу чуть подробнее. пока что мне кажется вовсе нецелесообразным гонять два потока, которые попеременно ждут один другого...


Название: Re: Синхронизация потоков, один из потоков не верно работает.
Отправлено: melifaro от Июль 29, 2009, 20:35
Это упрощенная, тестовая модель работы "сложной" программы.
Так как SuperStruct циклический список из n элементов то пока WhriteThread будет писать в него другой поток будет обрабатывать эти данные (здесь это не реализовано, тк модель нужна просто для того, чтобы понять как всё работает), и заносить результаты, например, в файл.


Название: Re: Синхронизация потоков, один из потоков не верно работает.
Отправлено: ритт от Июль 29, 2009, 21:52
совершенно иная задача - и подход должен быть другим.
надеюсь, вставок в середину списка не будет - это усложнит реализацию. а если не будет, можно смело использовать QList (добавление записи тоже O(1) ). и защищать нужно именно этот рабочий список, а не всё тело цикла, либо защищать индекс (или итератор), которым обходим список (но первый вариант проще).

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


Название: Re: Синхронизация потоков, один из потоков не верно работает.
Отправлено: melifaro от Июль 29, 2009, 22:35
К сожалению, список был написан(соответственно куча математических функций его обрабатывающих) давно и не мной, поэтому не могу вносить изменения в его структуру, у меня есть указатель на этот список и функции для работы с ним.

Цитировать
т.е., если я правильно понял задачу, один поток заполняет список, а второй простаивает в ожидании только в том случае, когда дошёл до конца списка (первый поток ещё не успел вставить новые элементы)
да, именно так.


Название: Re: Синхронизация потоков, один из потоков не верно работает.
Отправлено: ритт от Июль 29, 2009, 23:05
К сожалению, список был написан(соответственно куча математических функций его обрабатывающих) давно и не мной, поэтому не могу вносить изменения в его структуру, у меня есть указатель на этот список и функции для работы с ним.
тогда индекс и размер списка в посте выше заменить на текущий и последний элемент списка. в остальном всё так же.
первый поток (заполняющий список) не должен ждать второй (обрабатывающий); второй поток должен ждать первый только в случае, когда (cur == last && !end). если завершающий элемент списка неизвестен, end может означать "останов первого потока"...


Название: Re: Синхронизация потоков, один из потоков не верно работает.
Отправлено: melifaro от Июль 30, 2009, 07:39
Код:
первый поток (заполняющий список) не должен ждать второй (обрабатывающий);
Но если первый поток убежит вперед, он начнет перезаписывать ещё не считанные данные, в циклическом списке последний элемент указывает на первый.
Код:
если завершающий элемент списка неизвестен, end может означать "останов первого потока"...
Завершающий элемент какого списка? Если список с данными, то последний у него list->end(), если циклического списка, то first->prev.