Форум программистов, компьютерный форум, киберфорум
Delphi: Базы данных
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.71/7: Рейтинг темы: голосов - 7, средняя оценка - 4.71
0 / 0 / 0
Регистрация: 17.07.2012
Сообщений: 29
FoxPro

Многопоточность и BDE

17.10.2015, 16:01. Показов 1474. Ответов 6
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброе время суток, уважаемые форумчане. Назрела такая проблема: возникла необходимость сравнить две базы данных 1С (состав - *.dbf, *.cdx). Построение списка файлов *.dbf в одной и в другой базе решил сделать в двух потоках, которые запускаются одновременно. Среди прочего, в этих потоках определяется количество записей в каждой таблице сравниваемых баз данных. При запуске потоков выполняется только один, а второй попросту виснет без каких-либо исключениях. Сделал пошаговую трассировку - и действительно, второй поток виснет на инструкции
Delphi
1
TableTrh1.Active:= true;
"Что-то неладное", - подумал я. Причём неладное скорее всего в BDE.
По ссылке http://www.loginovprojects.ru/... deproblems ознакомился со статьёй и обратил внимание на следующее:
" Многопоточное приложение виснет при работе с таблицами базы данных. Проблема возникает из-за того, что во всех потоках по умолчанию используется объект TSession с именем "Default". Похоже, что в недрах BDE какие-то ресурсы защищаются от одновременного доступа с помощью критической секции, либо мьютекса. Перед выполнением SQL-запроса происходит захват объекта синхронизации, а после выполнения запроса захват данного объекта снимается. Если при выполнении запроса произойдет исключение, то снятие блокировки может не произойти (это бывает не всегда, а только в некоторых ситуациях, вероятно, где-то по ошибке пропущен оператор TRY..FINALLY), и выполнение любого запроса из параллельного потока приведет к его зависанию, т.к. он будет вечно ждать снятия блокировки. Для решения данной проблемы следует для каждого потока создавать свой объект TSession с уникальным именем SessionName, и назначать SessionName всем используемым в данном потоке DB-компонентам. SessionName лучше сделать глобально уникальным (это предотвратит зависание, если в качестве объекта синхронизации используется именованный мьютекс) ".
В каждом потоке динамически создаю объекты Tsession и TTable, однако результат тот же. Когда-то довольно часто работал с BDE, но компонентами TDataBase и TSeesion пользовался редко, практически позабыл про них. Может я что-то не так делаю (естественно, иначе работало бы ). Помогите, пожалуйста. Заранее благодарен.

Привожу код.

Первый поток:
Delphi
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
unit TThreadFiles_1;
 
interface
 
uses
  Classes, SysUtils, MD5, DB, DBTables;
 
type
  TThreadFiles1 = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
    procedure GetAllFilesDB( Path: string);
  end;
 
var
  SessionThr1: TSession;
  TableThr1: TTable;
implementation
     uses Unit1;
 
procedure TThreadFiles1.GetAllFilesDB( Path: string);
var
sRec: TSearchRec;
isFound: boolean;
begin
try
 
isFound := FindFirst( Path + '\*.*', faAnyFile, sRec ) = 0;
while isFound do
begin
if ( sRec.Name <> '.' ) and ( sRec.Name <> '..' ) then
begin
if ( sRec.Attr and faDirectory ) = faDirectory then
GetAllFilesDB( Path + '\' + sRec.Name);
 
 if (FileExists(Path + '\' + sRec.Name) and (ExtractFileExt(Path + '\' + sRec.Name) = '.DBF')) then
 begin
  InfoStruct1.NameFile.Add(Path + '\' + sRec.Name);
  InfoStruct1.MD5File.Add(MD5DigestToStr(MD5File(Path + '\' + sRec.Name)));
  inc(LengthArray1);
  setlength(InfoStruct1.CountRec, LengthArray1);
   ///
 
     TableThr1.TableName:= Path + '\' + sRec.Name;
        TableThr1.Active:= true;
    InfoStruct1.CountRec[LengthArray1-1]:= TableThr1.RecordCount;
    TableThr1.Active:= false;
    inc(ColRecDB1);
    synchronize(form1.SeeRecordsSrc1);
 end;
 
end;
 
isFound := FindNext( sRec ) = 0;
end;
FindClose( sRec );
except
   synchronize(form1.ThreadError1);
end;
 
end;
 
 
 
procedure TThreadFiles1.Execute;
begin
  
   SessionThr1:= TSession.Create(nil);
   SessionThr1.SessionName:= 'SN1';
     TableThr1:= TTable.Create(nil);
      TableThr1.SessionName:= SessionThr1.SessionName;
      SessionThr1.Active:= true;
  GetAllFilesDB(DirPath1);
   synchronize(form1.CancelProc1);
     SessionThr1.Active:= false;
     TableThr1.Free;
     SessionThr1.Free;
   
  terminate;
end;
 
end.
Второй поток:
Delphi
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
unit TThreadFiles_2;
 
interface
 
uses
  Classes, SysUtils, MD5, DB, DBTables;
 
type
  TThreadFiles2 = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
     procedure GetAllFilesDB( Path: string);
  end;
 
  var
  SessionThr2: TSession;
  TableThr2: TTable;
 
implementation
      uses Unit1;
 
 
procedure TThreadFiles2.GetAllFilesDB( Path: string);
var
sRec: TSearchRec;
isFound: boolean;
begin
try
 
isFound := FindFirst( Path + '\*.*', faAnyFile, sRec ) = 0;
while isFound do
begin
if ( sRec.Name <> '.' ) and ( sRec.Name <> '..' ) then
begin
if ( sRec.Attr and faDirectory ) = faDirectory then
GetAllFilesDB( Path + '\' + sRec.Name);
 
 if (FileExists(Path + '\' + sRec.Name) and (ExtractFileExt(Path + '\' + sRec.Name) = '.DBF')) then
 begin
 
  InfoStruct2.NameFile.Add(Path + '\' + sRec.Name);
  InfoStruct2.MD5File.Add(MD5DigestToStr(MD5File(Path + '\' + sRec.Name)));
  inc(LengthArray2);
    setlength(InfoStruct2.CountRec, LengthArray2);
 
 TableThr2.TableName:= Path + '\' + sRec.Name;
        TableThr2.Active:= true; //ОСТАНАВЛИВАЕТСЯ ВЫПОЛНЕНИЕ БЕЗ СООБЩЕНИЙ ОБ ОШИБКЕ
    InfoStruct2.CountRec[LengthArray2-1]:= TableThr2.RecordCount;
    TableThr2.Active:= false;
   inc(ColRecDB2);
    synchronize(form1.SeeRecordsSrc2);
 end;
 
end;
 
isFound := FindNext( sRec ) = 0;
end;
FindClose( sRec );
except
   synchronize(form1.ThreadError2);
end;
 
end;
 
procedure TThreadFiles2.Execute;
begin
    SessionThr2:= TSession.Create(nil);
      SessionThr2.SessionName:= 'SN2';
        TableThr2:= TTable.Create(nil);
      TableThr2.SessionName:= SessionThr2.SessionName;
      SessionThr2.Active:= true;
   GetAllFilesDB(DirPath2);
   synchronize(form1.CancelProc2);
       SessionThr2.Active:= false;
     TableThr2.Free;
     SessionThr2.Free;
  terminate;
end;
 
end.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
17.10.2015, 16:01
Ответы с готовыми решениями:

Ремонт Прошу совета ПММ Krona BDE 4507 EU, ПММ Krona BDE 4507 EU Ошибка Е3 исчезла после чистки
Здравствуйте мастера, случай вот какой,3 месяца назад поступила посудомоечная машина Krona BDE 4507 EU с ошибкой Е3 сразу скажу что редко...

BDE
Добрый вечер, немогли бы мне помочь в создании программы в дельфи, суть в задачи в следующем: Разработать любое программное обеспечения...

BDE
Подскажите пожалуйста как вставить в инстоляшку BDE и прописать alias работаю в inno setup? Если можно подробно, я начинающий и в этом...

6
5966 / 4542 / 1094
Регистрация: 29.08.2013
Сообщений: 28,151
Записей в блоге: 3
17.10.2015, 17:27
1. ну сравнить базы можно и не таким способом

2. я не вижу динамическое создание ни TTable, ни TSession

вот так надо создавать
Delphi
1
2
3
4
5
6
7
8
9
var
MyTable: TTable;
begin
MyTable := TTable.Create(Self);
with MyTable do
begin
DatabaseName := 'DBDemos';
TableName := 'Test.DB';
end
0
0 / 0 / 0
Регистрация: 17.07.2012
Сообщений: 29
17.10.2015, 17:58  [ТС]
Создание компонентов происходит в методе Execute потоков (если обратите внимание на мой код, начиная со строчки 70...). Согласен, что при создании компонента при отсутствии желания указывать на родителя лучше использовать переменную Self, а не nil, как в моём случае (хотя (могу ошибаться ) эффект один и тот же).
Если обратите внимание на процедуру GetAllFilesDB(DirPath1) (что касается первого потока, во втором всё аналогично), то увидите, что функция анализирует необходимую папку (переменная DirPath1, DirPath2) на наличие файлов *.dbf и загружает их список в память... Имена таблиц (полный путь к таблицам) меняются благодаря присвоения соответствующему свойству компонента TTable значения переменной sRec.Name типа TSearchRec... Но хватит об этом...
Самое смешное - экспериментировал с кодом на работе в результате чего один из потоков сделал не автоматически запускающимся
Delphi
1
ThreadFiles2:= TThreadFiles2.Create(true); //ну невнимательный дурак, что поделаешь
Заметил до размещения поста, извините. Так вот, после добавления в проект динамического создания компонента TSession и исправления моей ошибки ВСЁ ЗАРАБОТАЛО!
Одного не могу понять - почему так? Я согласен, что необходимо создавать разные сессии, если обращение к одной и той же базе данных осуществляется из разных потоков. Однако мои потоки работают с базами, физически расположенными в разных директориях, а значит расцениваются как совершенно разные.
Буду благодарен за объяснение.
0
5966 / 4542 / 1094
Регистрация: 29.08.2013
Сообщений: 28,151
Записей в блоге: 3
17.10.2015, 18:02
Flex_, не знаю почему именно так, но я бы на вашем месте загрузил обе базы в MS SQL и все сделал бы там.
0
0 / 0 / 0
Регистрация: 17.07.2012
Сообщений: 29
17.10.2015, 18:33  [ТС]
Кстати, Delphi автоматически генерирует объект Session в каждом приложении, которое работает с базами данных. И как было указано в статье, представленной выше, имеет имя default.
Скорее всего, если выполнять операции над базами данных в потоках (фактически отдельные приложения), объект TSession не создаётся, либо создаётся, но при количестве потоков более одного происходит конфликт имён (если имена не назначать явно - n-ное количество "default").
Если неправильно рассудил, исправьте.

Добавлено через 53 секунды
qwertehok, Добавлено через 3 минуты
Два одновременных потока не жизненная необходимость, а скажем так "личный каприз". Идея же - существует две базы 1С 7.7 (практически от них отошли (прошлый век, скажем так))... 1С работает в файл-серверной архитектуре, то есть располагается на каком-то диске и расшарена. Всё руки не доходили склипать батник или что-то своими ручками в Делфи для резервного копирования (причём не только различных баз данных, но и важных документов и иных файлов). Так вот, у меня к примеру есть резервная копия базы 1С, но в ней не хватает записей за 2 дня (не было возможности сделать рез. копию, а пользователь при этом работал и вбивал данные). При возникновении проблемы с этой БД, я открываю её и резервную копию двухдневной давности в моей программе. Программа проходит по файлам *.dbf и формирует MD5-отпечаток. Если MD-5 отпечатки сравниваемых таблиц не равен, значит базы отличаются. Остаётся обратиться к нужной таблице и выяснить какие поля изменил и какие записи добавил пользователь и внести эти изменения в стабильно работающую базу данных.
А про мою задумку и MS SQL можно по-подробнее.
0
3530 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
17.10.2015, 19:30
Цитата Сообщение от Flex_ Посмотреть сообщение
что-то не так делаю
Плодишь практически одинаковые классы потоков.
Делают-то они у тебя одно и тоже, но с разными исх.данными..
0
5966 / 4542 / 1094
Регистрация: 29.08.2013
Сообщений: 28,151
Записей в блоге: 3
17.10.2015, 20:08
Flex_, ставь пользователю MS SQL (если база меньше 10 гигов то достаточно будет бесплатной версии), настраивай ежедневный бэкап (хочешь полный, хочешь с diff'ами) и не морочь голову с Delphi

Если MD-5 отпечатки сравниваемых таблиц
Извини, но что такое MD5 таблицы? Бывает только хэш текста.

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

Нет слов
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
17.10.2015, 20:08
Помогаю со студенческими работами здесь

Избавится от BDE
Добрый день, форумчане! Написали программу на Delphi 7 с подключением через: ADOConnection1.ConnectionString := ...

BDE и SQL2012
Есть некий громадный архаизм, реализованный на BDE. При переходе на SQL2012 обнаружилось, что программа напрочь отказывается работать с...

BDE Admin
Нужно создать Исталлятор с программой... а к ней идет еще bde administrator v5.01. Вот хотелось что бы её установить и что меня...

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

Работа с BDE
Здравствуйте. Получил в университете задание по организиции простой БД средствами delphi7 и bde. Сразу оговорюсь, что делаю это...


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

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru