Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/8: Рейтинг темы: голосов - 8, средняя оценка - 4.75
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648

Работа с потоками

21.07.2018, 10:04. Показов 1579. Ответов 6
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем здравствуйте.

Программа обращается к некоторому файлу по локальной сети на удалённом компьютере. Из этого файла в программу считывается информация в виде массива байтов (массива структур). Если сетевой путь указан несуществующий (старая конфигурация, отключена сеть), то это обращение может занять несколько секунд и только потом появится сообщение системы
или разработчика о ошибочном пути к сетевому файлу. (Не понимаю зачем разработчики всех Windows это сделали для локальной сети, а не только для интернета.) На лицо имеем нежелательные тормоза всего приложения.
А если это обращение будет производится ещё и в цикле таймера, тормоза основной программы будут особо ярко выражены.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#pragma option push -a1
struct CurrData
{
    UINT t;         // 4
    USHORT d;       // 2
    USHORT m;       // 2
    USHORT y;       // 2
    float v[100];   // 100*4
}cur = {};
#pragma option pop
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
    Label1->Caption = IntToStr(sizeof(cur));
}
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
    char* sFName = "\\\\Dis\\D\\main.dat"; // Несуществующий сетевой путь
    ifstream in;
    in.open (sFName, ios::binary);
    if (!in)
    {
        Label1->Caption = "Файл не  открыт";
        return;
    }
    in.read((char*)&cur, sizeof(cur));
    in.close();
    Label1->Caption = IntToStr(cur.t);  // Сюда мы вообще не попадаем
}
void __fastcall TForm1::Timer2Timer(TObject *Sender)
{
     // Для оценки задержки при несуществующем сетевом имени
    static int n;
    Label2->Caption = IntToStr(n);
    n++;
}


Возникла идея вынести обращение к некоторому файлу по локальной сети в отдельный поток, пусть уж в случае отсутствия сетевого соединения тормозится не вся программа, а только он.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#pragma option push -a1
struct CurrData
{
    UINT t;         // 4
    USHORT d;       // 2
    USHORT m;       // 2
    USHORT y;       // 2
    float v[100];   // 100*4
}cur = {};
#pragma option pop
// Поток для чтения
class ReadThread : public TThread
{
 private:
        void __fastcall ShowData(); // Вывод принятых байтов на экран основной программы
 protected:
        void __fastcall Execute();  // Основная функция потока
 public:
        __fastcall ReadThread(bool CreateSuspended);    // Конструктор потока
};
ReadThread *reader;     // Объект потока ReadThread
// Конструктор потока ReadThread, по умолчанию пустой
__fastcall ReadThread::ReadThread(bool CreateSuspended) : TThread(CreateSuspended)
{}
void __fastcall ReadThread::Execute() // Главная функция потока
{
    while(1)
    {
        //char* sFName = "D:\\main.dat";
        char* sFName = "\\\\Dis\\D\\main.dat";
        ifstream in;
        in.open (sFName, ios::binary);
        if (!in) continue;
        in.read((char*)&cur, sizeof(cur));
        in.close();
        Synchronize(ShowData);              // Вызываем функцию для вывода данных на экран
    }
}
void __fastcall ReadThread::ShowData()  // Выводим принятые байты на экран
{
    Form1->Label3->Caption = IntToStr(cur.t);
}
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
    reader = new ReadThread(false);     // Cоздать и запустить поток чтения
    reader->FreeOnTerminate = true;     // Поток автоматически уничтожится после завершения
}

Вопросы: Как приостановить и возобновить поток (клик по Button из основной программы)? Как уменьшить его частоту (Pause) чтобы не так сильно грузить процессор? Где в представленном коде вывести сообщение о не существовании указанного сетевого пути? Что в предложенном коде лишнее?
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
21.07.2018, 10:04
Ответы с готовыми решениями:

Работа с потоками
Доброго времени суток. Нужно создать программу, в которой имеется как минимум 3 потока ( форма + 2 дополнительных ). Задачи решаемые в...

Работа с потоками
Помогите В одной функции идёт больше одного патока надо чтобы все потоки остановились пока один выполняется и так все по очереди ...

Работа с 2-мя потоками
Здравствуйте! Ребята, помогите, разобраться решил уделить внимание потокам в программе и изучить как их лучше применять. Для этого открыл...

6
 Аватар для Meoww
8 / 8 / 2
Регистрация: 02.10.2014
Сообщений: 112
22.07.2018, 11:14
Если не заморачиваться:

Остановка thread->Suspend()
Запуск thread->Resume()

Воткните в ваш while (и никогда не делайте впредь подобные циклы без разгрузки) в любом месте Sleep(1);
У вас же есть Synchronize(ShowData); воткните аналог для показа ошибки пути. Или выйдите из цикла и
по завершению потока покажите ошибку, ну или не покажите, если путь есть

P.S. к слову, ваш поминутный Synchronize(ShowData); сводит на нет мороку с выносом загрузки в поток,
и добавляет проблем с нагрузкой - порциями хоть выводите как то
1
Практикантроп
 Аватар для nick42
4841 / 2726 / 534
Регистрация: 23.09.2011
Сообщений: 5,798
23.07.2018, 08:35
А просто проверка по таймеру на существование файла не может решить проблему?
C++
1
2
3
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
   if(FileExists("\\\\<server>\\<path>\\<file>")) CheckBox1->Enabled = true; . . .
(Здесь вместо слов в угловых скобках подставить реальные имена). И опять же по таймеру отправлять запросы туда, где есть разрешенные ссылки (у меня в примере checkbox).

Добавлено через 3 минуты
П.С. хотя нет, - при несуществующем пути всё равно тормозит.
1
 Аватар для Meoww
8 / 8 / 2
Регистрация: 02.10.2014
Сообщений: 112
23.07.2018, 12:44
в старые добрые времена, когда ассемблер был молодым..) одним словом, напишите подобный костылище, засуньте его в поток и все
C++
1
2
3
4
5
6
7
8
9
10
11
while(var1)
{
    while(var2)
    {
        ...
        if(error) var2 = false;
        Sleep(1)
    }
    Sleep(50);
}
// снаружи управляйте переменными var1 и var2
1
 Аватар для jkrnd
179 / 69 / 13
Регистрация: 22.12.2015
Сообщений: 2,648
28.07.2018, 12:38  [ТС]
Meoww, я сделал так:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#pragma option push -a1
struct CurrData
{
    UINT t;         // 4
    USHORT d;       // 2
    USHORT m;       // 2
    USHORT y;       // 2
    float v[100];   // 100*4
}cur = {};
#pragma option pop
 
char* sFName = "\\\\Panelts\\D\\spt.dat";
bool errRead;
// Поток для чтения
class ReadThread : public TThread
{
 private:
        void __fastcall ShowData(); // Вывод принятых байтов на экран основной программы
 protected:
        void __fastcall Execute();  // Основная функция потока
 public:
        __fastcall ReadThread(bool CreateSuspended);    // Конструктор потока
};
ReadThread *reader;     // Объект потока ReadThread
// Конструктор потока ReadThread, по умолчанию пустой
__fastcall ReadThread::ReadThread(bool CreateSuspended) : TThread(CreateSuspended)
{}
void __fastcall ReadThread::Execute() // Главная функция потока
{
    while(1)
    {
        Sleep(200);
        ifstream in;
        in.open (sFName, ios::binary);
        if (in)     // Чтение произведено
        {
            errRead = false;    // Сбрасываем флаг ошибки
            in.read((char*)&cur, sizeof(cur));
            in.close();
        }
        else errRead = true;                // Чтения не произведено, поднимаем флаг ошибки
        Synchronize(ShowData);              // Вызываем функцию для вывода данных на экран
    }
}
//---------------------------------------------------------------------------
void __fastcall ReadThread::ShowData()  // Выводим принятые байты на экран
{
 
    Form1->Label4->Caption = "errRead = " +IntToStr(errRead);
    if (errRead) Form1->Label1->Caption = "err";
        else  Form1->Label1->Caption = IntToStr(cur.t);
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
    Form1->Label3->Caption = sFName;
 
    reader = new ReadThread(false);     // Cоздать и запустить поток чтения
    //reader = new ReadThread(true);     // Cоздать поток чтения в остановленном состоянии. Будем запускать его по мере необходимости
    reader->FreeOnTerminate = true;     // Поток автоматически уничтожится после завершения
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer2Timer(TObject *Sender)
{
     // Для оценки задержки при несуществующем сетевом имени
    static int n;
    Label2->Caption = IntToStr(n);
    n++;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    sFName = "\\\\Panelts\\D\\spt.dat";
    Form1->Label3->Caption = sFName;
}
//---------------------------------------------------------------------------
 
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    sFName = "\\\\No\\D\\spt.dat";
    Form1->Label3->Caption = sFName;
}
//---------------------------------------------------------------------------
 
 
void __fastcall TForm1::Button3Click(TObject *Sender)
{
    reader->Suspend();      // Приостановить поток, пока он не потребуется снова
}
//---------------------------------------------------------------------------
 
void __fastcall TForm1::Button4Click(TObject *Sender)
{
    reader->Resume();       // Активировать поток
}
//---------------------------------------------------------------------------

Ошибок не вижу.
Цитата Сообщение от Meoww Посмотреть сообщение
поминутный Synchronize(ShowData); сводит на нет мороку с выносом загрузки в поток,
и добавляет проблем с нагрузкой
- это я вообще не понял, если можно разъясните.
Кнопка 2 присваивает переменной sFName несуществующее сетевое имя, кнопка 1 присваивает переменной sFName существующее сетевое имя, ничего не тормозит. Частота проверочного Timer2 = 1000 мсек
0
 Аватар для Meoww
8 / 8 / 2
Регистрация: 02.10.2014
Сообщений: 112
28.07.2018, 12:44
Лучший ответ Сообщение было отмечено jkrnd как решение

Решение

Я вам в примере показал как можно обойтись без (от слова совсем) reader->Suspend(); и reader->Resume(); и не морочить себе голову (вы завели себе поток, неее маловато будет, надо еще таймер к этому потоку прикрутить)))).

Запустили поток один раз и пусть себе крутится до окончания программы.

Что же до Synchronize(ShowData) - в вашем случае да - это некритично. Но в случае частого обращения из потока к форме, эта конструкция может не кисло тормозить (конечно в зависимости от начинки ShowData). Не вдаваясь в подробности, считайте что каждый Synchronize(ShowData) - то же самое, что подобный код в таймере в главном потоке.
1
 Аватар для Human_foot
156 / 114 / 36
Регистрация: 27.06.2018
Сообщений: 257
28.07.2018, 13:35
reader->Suspend();
Нельзя так делать ни в коем случае!!! Очень часто встречается приостановка/запуск, однако эти методы небезопасен и считаются устаревшими. http://docwiki.embarcadero.com... ad.Suspend
Дело в том, что поток может быть заморожен даже в тот момент, когда выполняется Synchronize. "Заморозку" можно использовать для отладки, а не для релиза.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
28.07.2018, 13:35
Помогаю со студенческими работами здесь

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

Работа с потоками через OpenDialog
Как сделать чтобы в таком коде мы могли выбрать файл (при помощи OpenDialog) с которого будем считывать ? ifstream A (&quot;FILE...

Работа с потоками и процессами windows
Почему выбивает ошибку в строке PInf *Inf ? Нашёл пример в методичке..помогите разобраться #include &lt;vcl.h&gt; ...

Работа с потоками
Программа: парсер, по нажатию на кнопку, она начинает свою работу (конечно же в отдельном потоке). Получив данные с сайта, нам нужно эти...

Работа с потоками
Помогите начинающему программисту!!! Нужно написать программу в которой есть два дочерних потока. В главном потоке интовой переменной...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
Переходник USB-CAN-GPIO
Eddy_Em 20.03.2026
Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и был разработан. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто. . .
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru