0 / 0 / 0
Регистрация: 17.07.2012
Сообщений: 31
FoxPro

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

17.10.2015, 16:01. Показов 1529. Ответов 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
5989 / 4564 / 1096
Регистрация: 29.08.2013
Сообщений: 28,206
Записей в блоге: 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
Сообщений: 31
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
5989 / 4564 / 1096
Регистрация: 29.08.2013
Сообщений: 28,206
Записей в блоге: 3
17.10.2015, 18:02
Flex_, не знаю почему именно так, но я бы на вашем месте загрузил обе базы в MS SQL и все сделал бы там.
0
0 / 0 / 0
Регистрация: 17.07.2012
Сообщений: 31
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
5989 / 4564 / 1096
Регистрация: 29.08.2013
Сообщений: 28,206
Записей в блоге: 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
Ответ Создать тему
Опции темы

Новые блоги и статьи
Отчёт о спецтехнике находящейся в ремонте
Maks 20.04.2026
Отчёт из решения ниже размещен в конфигурации КА2. Задача: отобразить спецтехнику, которая на данный момент находится в ремонте. Есть нетиповой документ "Заявка на ремонт спецтехники" который. . .
Памятка для бота и "визитка" для читателей "Semantic Universe Layer (Слой семантической вселенной)"
Hrethgir 19.04.2026
Сгенерировано для краткого описания по случаю сборки и компиляции скелета серверного приложения. И пусть после этого скажут, что статьи сгенерированные AI - туфта и не интересно. И это не реклама -. . .
Запрет удаления строк ТЧ документа при определенном условии
Maks 19.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "Аккумуляторы", разработанного в конфигурации КА2. У данного документа есть ТЧ, в которой в зависимости от прав доступа. . .
Модель заражения группы наркоманов
alhaos 17.04.2026
Условия задачи сформулированы тут Суть: - Группа наркоманов из 10 человек. - Только один инфицирован ВИЧ. - Колются одной иглой. - Колются раз в день. - Колются последовательно через. . .
Мысли в слух. Про "навсегда".
kumehtar 16.04.2026
Подумалось тут, что наверное очень глупо использовать во всяких своих установках понятие "навсегда". Это очень сильное понятие, и я только начинаю понимать край его смысла, не смотря на то что давно. . .
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица. Задача: зафиксировать три левых колонки в отчете. Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) / / . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru