Russian Qt Forum
Ноябрь 26, 2024, 05:17 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Синхронизация потоков, один из потоков не верно работает.  (Прочитано 7017 раз)
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. Если менять число элементов, то всё равно не досчитывает. Пробовал использовать семафоры - результат тот же. Я чего-то не понимаю. Подскажите пожалуйста.
Записан
ритт
Гость
« Ответ #1 : Июль 28, 2009, 23:53 »

что такое curr->prev->num? где сигнал?
впечатление, что ты не хочешь получить ответ на свой вопрос...
Записан
melifaro
Гость
« Ответ #2 : Июль 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;
Записан
ритт
Гость
« Ответ #3 : Июль 29, 2009, 08:23 »

советую внимательно почитать док по Wait Conditions Example. подозреваю, что код выше использован как раз из этого примера, но отличия имеются.
Записан
Winstrol
Гость
« Ответ #4 : Июль 29, 2009, 09:39 »

Следующая ситуация:
Один поток заносит данные в определенную структуру (обращается к ней по указателю), другой обсчитывает и пишет данные в файл.

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

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

По сему, до того как ознакомитесь с
отвечать на поставленный вопрос, без внятного понимания автором, чего он хочет, не вижу смысла.
« Последнее редактирование: Июль 29, 2009, 09:41 от Winstrol » Записан
melifaro
Гость
« Ответ #5 : Июль 29, 2009, 18:50 »

По-моему ситуацию я описал весьма конкретно. И задача тоже ясна.
Цитировать
Пользование низкоуровневыми примитивами синхронизации вроде QWaitCondition вам запрещено, примите это как данность.
Что тогда посоветуешь использовать?
Похоже "читайте Assistant" самый частый ответ на форуме.
Записан
ритт
Гость
« Ответ #6 : Июль 29, 2009, 19:17 »

Похоже "читайте Assistant" самый частый ответ на форуме.
так и есть.
при желании можно было бы составить статистику, показывающую, что большинство вопросов задаётся от нежелания/неумения читать документацию...

По-моему ситуацию я описал весьма конкретно. И задача тоже ясна.
Что тогда посоветуешь использовать?
опиши задачу чуть подробнее. пока что мне кажется вовсе нецелесообразным гонять два потока, которые попеременно ждут один другого...
Записан
melifaro
Гость
« Ответ #7 : Июль 29, 2009, 20:35 »

Это упрощенная, тестовая модель работы "сложной" программы.
Так как SuperStruct циклический список из n элементов то пока WhriteThread будет писать в него другой поток будет обрабатывать эти данные (здесь это не реализовано, тк модель нужна просто для того, чтобы понять как всё работает), и заносить результаты, например, в файл.
Записан
ритт
Гость
« Ответ #8 : Июль 29, 2009, 21:52 »

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

т.е., если я правильно понял задачу, один поток заполняет список, а второй простаивает в ожидании только в том случае, когда дошёл до конца списка (первый поток ещё не успел вставить новые элементы)
Записан
melifaro
Гость
« Ответ #9 : Июль 29, 2009, 22:35 »

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

Цитировать
т.е., если я правильно понял задачу, один поток заполняет список, а второй простаивает в ожидании только в том случае, когда дошёл до конца списка (первый поток ещё не успел вставить новые элементы)
да, именно так.
« Последнее редактирование: Июль 29, 2009, 22:37 от melifaro » Записан
ритт
Гость
« Ответ #10 : Июль 29, 2009, 23:05 »

К сожалению, список был написан(соответственно куча математических функций его обрабатывающих) давно и не мной, поэтому не могу вносить изменения в его структуру, у меня есть указатель на этот список и функции для работы с ним.
тогда индекс и размер списка в посте выше заменить на текущий и последний элемент списка. в остальном всё так же.
первый поток (заполняющий список) не должен ждать второй (обрабатывающий); второй поток должен ждать первый только в случае, когда (cur == last && !end). если завершающий элемент списка неизвестен, end может означать "останов первого потока"...
Записан
melifaro
Гость
« Ответ #11 : Июль 30, 2009, 07:39 »

Код:
первый поток (заполняющий список) не должен ждать второй (обрабатывающий);
Но если первый поток убежит вперед, он начнет перезаписывать ещё не считанные данные, в циклическом списке последний элемент указывает на первый.
Код:
если завершающий элемент списка неизвестен, end может означать "останов первого потока"...
Завершающий элемент какого списка? Если список с данными, то последний у него list->end(), если циклического списка, то first->prev.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.046 секунд. Запросов: 21.