0 / 0 / 1
Регистрация: 29.07.2012
Сообщений: 16
1

Access Violation при вызове метода Open для Sqlquery из потока

23.12.2014, 10:17. Показов 2126. Ответов 11
Метки нет (Все метки)

Здравствуйте, очень нужна помощь. Использую dbexpress для работы с Oracle. В проекте есть модуль данных, на котором расположены компоненты dbexpress, в основном коде вызываю процедуру из модуля в отдельном потоке
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
New(threadParam);
   try
    if ReportKind.report_47 then
      begin
        threadParam.repDate := DateTimePicker1.Date;;
        threadParam.rep47 := True;
        threadParam.rep34 := False;
        threadId := BeginThread(nil, 0, @SvedWork.dReport, threadParam, CREATE_SUSPENDED, someId);
        SetThreadPriority(threadId, THREAD_PRIORITY_LOWEST);
        ResumeThread(threadId);
        unThreadWorking.fmThreadWorking.ShowModal;
        //dmSveden.dmSved.tmTimer.Enabled := False;
        //ShowMessage('test');
      end
 
    else
      begin
        threadParam.repDate := DateTimePicker1.Date;
        threadParam.rep47 := False;
        threadParam.rep34 := True;
        threadId := BeginThread(nil, 0, @SvedWork.dReport, threadParam, CREATE_SUSPENDED, someId);
        SetThreadPriority(threadId, THREAD_PRIORITY_NORMAL);
        ResumeThread(threadId);
        unThreadWorking.fmThreadWorking.ShowModal;
      end;
   finally
      if threadId = 0 then
        Dispose(threadParam);
   end;
    CloseHandle(threadId);
... в потоке выполняется код
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
procedure dReport(Params: Pointer);
var
  i,j :Integer;
  sqlString: string;
  p: TParamRecord;
  iniFile:TIniFile;
  uId: Integer;
begin
  p:= PPointRecord(Params)^;
  iniFile := TIniFile.Create(GetCurrentDir + '\settings.ini');
  with dmSved.dbexSved do
    begin
      Params.Values['Database'] := iniFile.ReadString('Oracle', 'OraServer', '' );
      uId := StrToInt(iniFile.ReadString('Oracle', 'OraUser', '' ));
      case  uId of   {Case'îì âûáèðàåì, ïîä êàêèì ïîëüçîâàòåëåì ïîäêëþ÷àåìñÿ ê áàçå}
        1:
          begin
            Params.Values['User_name'] := 'gaidev';
            Params.Values['Password'] := 'mainowner';
          end;
        2:
          begin
            Params.Values['User_name'] := 'roland';
            Params.Values['Password'] := '';
          end;
      end;
    end;
 
 
  if p.rep47 then
    sqlString := 'SELECT ' +
                                'sp.kod, ' +
                                'sp.n2 as sp_n2, ' +
                                'sv.DAY_IN, ' +
                                'sv.N1, ' +
                                '0,' +          //-- âîëøåáíûé íîëèê íàäî çàìåíèòü íà äàííû
                                'sv.DPS_FACT, ' +
                                'sv.DTP_IRON,  ' +
                                'sv.VPDD,  ' +
                                'sv.N4,  ' +
                                'sv.VIDEO,  ' +
                                'sv.N6,  ' +
                                'sv.DPS1,  ' +
                                'sv.N11,  ' +
                                'sv.SPEED_VLT,  ' +
                                'sv.NPP, ' +
                                'sv.N1223, ' +
                                'sv.P1, ' +
                                'sv.P2,  ' +
                                'sv.N53, ' +
                                'sv.N1224,  ' +
                                'sv.N15,  ' +
                                'sv.N17, ' +
                                'sv.LPU,  ' +
                                'sv.N23, ' +
                                'sv.COMMUN_SRV,  ' +
                                'sv.UDC,  ' +
                                'sv.P5, ' +
                                'sv.P3,  ' +
                                'sv.P4,  ' +
                                'sv.DPRED,  ' +
                                'sv.ATP, ' +
                                'sv.P7,  ' +
                                'sv.P6,  ' +
                                'sv.TPRED,  ' +
                                'sv.P10,  ' +
                                'sv.P11,  ' +
                                'sv.P12,  ' +
                                'sv.PPRED,  ' +
                                'sv.P13,  ' +
                                'sv.D1,   ' +
                                'sv.P15, ' +
                                'sv.P18,  ' +
                                'sv.P20, ' +
                                'sv.N33,  ' +
                                'sv.N35,  ' +
                                'sv.N37,  ' +
                                'sv.N38,  ' +
                                'sv.N39,  ' +
                                'sv.N41,  ' +
                                'sv.N43   ' +
                            'FROM sv_spw sp LEFT JOIN sveden sv ON sp.kod = sv.rajon and sv.day_in = to_date(:date, ''dd.mm.yyyy'') where sp.kod not in (100, 1047, 1048, 1049)'
  else
    sqlString :=  'SELECT ' +
                                  'sp.kod, ' +
                                  'sp.n1 as sp_n1, ' +
                                  'sv.DAY_IN, ' +
                                  'sv.VPDD,  ' +
                                  'sv.N4,  ' +
                                  'sv.VIDEO,  ' +
                                  'sv.N6,  ' +
                                  'sv.DPS1,  ' +
                                  'sv.N11,  ' +
                                  'sv.SPEED_VLT,  ' +
                                  'sv.NPP, ' +
                                  'sv.N1223, ' +
                                  'sv.P1, ' +
                                  'sv.P2,  ' +
                                  'sv.N53, ' +
                                  'sv.N17, ' +
                                  'sv.LPU,  ' +
                                  'sv.N23, ' +
                                  'sv.COMMUN_SRV,  ' +
                                  'sv.UDC,  ' +
                                  'sv.P5, ' +
                                  'sv.P3,  ' +
                                  'sv.P4,  ' +
                                  'sv.DPRED,  ' +
                                  'sv.ATP, ' +
                                  'sv.P7,  ' +
                                  'sv.P6,  ' +
                                  'sv.TPRED,  ' +
                                  'sv.P10,  ' +
                                  'sv.P11,  ' +
                                  'sv.P12,  ' +
                                  'sv.PPRED,  ' +
                                  'sv.P13,  ' +
                                  'sv.D1,   ' +
                                  'sv.P20, ' +
                                  'sv.N33,  ' +
                                  'sv.N35  ' +
                              'FROM sv_spw sp LEFT JOIN sveden sv ON sp.kod = sv.rajon and sv.day_in = to_date(:date, ''dd.mm.yyyy'') where sp.kod not in (100, 1047, 1048, 1049)';
 
 
       with dmSved do
         begin
           if qSveden.Active =  True then
              qSveden.Close;
 
 
           qSveden.ParamByName('date').AsBCD := p.repDate;
           qSveden.SQL.Add(sqlString);
           qSveden.Active := True;
           if not qSveden.IsEmpty then
             begin
               arrSvedData := VarArrayCreate([0, qSveden.RecordCount , 0, qSveden.FieldCount - 4], varVariant);
               for i := 0 to VarArrayHighBound(arrSvedData, 1) do
                 begin
                   for j := 0 to VarArrayHighBound(arrSvedData, 2) do
                    arrSvedData[i,j] := qSveden.Fields.Fields[j + 3].AsInteger;  //[j+3] - èñêëþ÷àåì ïîëÿ 'sp.kod, sp_n1, sv.DAY_IN
                   qSveden.Next;
                 end;
               qSveden.Close;
             end
           else
            begin
              ShowMessage('Èçâèíèòå, íî äàííûõ íà óêàçàííóþ äàòó ïðåäîñòàâëåíî íå áûëî.');
              qSveden.Close;
              Exit;
            end;
         end;
При вызове метода Open или Active := true получаю Exception EAccessViolation in module dbexpora.dll at 00011BC9... и так далее.
При этом, подобный код работает в потоке через TThread и всё работает нормально. В чём может быть дело?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.12.2014, 10:17
Ответы с готовыми решениями:

Access violation в вызове метода объекта
Здравствуйте! Помогите, пожалуйста, разобраться в чем дело, почему вдруг возникает ошибка First...

Access violation при вызове mysql_errno
День добрый!!! Столкнулся с проблемой при вызове функции mysql_errno(). #include <vcl.h>...

Access violation при вызове конструктора
Здравствуйте! У меня при вызове конструктора возникает ошибка. Access violation at adress...

Access Violation при вызове функции из DLL
Доброго времени. У меня загвоздочка с вызовом одной функции из длл (описание функции лежит в док...

11
2649 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,725
23.12.2014, 10:50 2
Цитата Сообщение от Childeroland Посмотреть сообщение
При вызове метода Open или Active := true получаю Exception EAccessViolation ..
..код работает в потоке через TThread и всё работает нормально
Сам-то понял что сказал ?
"Получаю Exception" и при этом "всё работает нормально")

Любой коннект к Ораклу в любом потоке должен быть в блоке CoInitializeEx/CoUnInitializeEx.
В осн.потоке VCL-приложения за тебя это неявно сделает компилятор, но в доп.потоках эти действия ты должен делать сам ручками.

Цитата Сообщение от Childeroland Посмотреть сообщение
ShowMessage('Извините
Не извиним)
В доп.потоке этот вызов не допустим - в нем идет неявное обращение к VCL-форме.
0
0 / 0 / 1
Регистрация: 29.07.2012
Сообщений: 16
23.12.2014, 11:10  [ТС] 3
Цитата Сообщение от mss Посмотреть сообщение
Сам-то понял что сказал ?
"Получаю Exception" и при этом "всё работает нормально")

Любой коннект к Ораклу в любом потоке должен быть в блоке CoInitializeEx/CoUnInitializeEx.
В осн.потоке VCL-приложения за тебя это неявно сделает компилятор, но в доп.потоках эти действия ты должен делать сам ручками.


Не извиним)
В доп.потоке этот вызов не допустим - в нем идет неявное обращение к VCL-форме.
Нужно внимательно посмотреть код и тогда станет ясно, что поток я создаю через BeginThread, это совсем не то, что создавать поток через класс TThread и вызывать его методом Execute, это во-первых, во-вторых, я, конечно же, знаю что ShowMessage не катит в данном случае, сначала потока не было, а была обычная функция в отдельном модуле... Мне просто лень было комментировать этот вызов, на него можно не обращать внимания....
0
2649 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,725
23.12.2014, 11:23 4
Цитата Сообщение от Childeroland Посмотреть сообщение
поток я создаю через BeginThread, это совсем не то, что создавать поток через класс TThread и вызывать его методом Execute
Да ну ? Неужели ?
И в чем же, по-твоему, заключается принципиальная разница между этими двумя способами задействования доп.нити ?

станет ясно
Это только тебе ясно)
А более никому не ясно где и как ты создаешь объект qSveden. И создаешь ли вообще).. Судя по исключению, ты его попросту не создаешь.
0
0 / 0 / 1
Регистрация: 29.07.2012
Сообщений: 16
23.12.2014, 11:46  [ТС] 5
эээ, я глупенький программист, на надо на меня наезжать =)
есть ли смысл разбираться в принципах создания потоков, используя Execute Tthread'a или используя BeginThread? Мне они не ведомы сейчас, и нет времени об этом думать, но это не отменяет того факта, что создавая поток по всем правилам класса TThread (под правилами я в данном случае понимаю примеры из справок и интернета), обращение к Oracle проходит нормально. Правда, действительно, там я использовал CoInitialize, правда, по другой причине, но работает. Мне же надо использовать BeginThread (кстати, он мне без особого труда позволяет в другой модуль передать любое количество параметров, можно ли это считать принципиальной разницей?).
qSveden - компонент TSqlQuery со вкладки dbexpress, он находится на модуле данных dmSved... если бы я его не создал, я бы не смог установить параметры его, как то текст SQL, значит, он создан, прихожу я к такому выводу.
... Добавил CoInitializeEx(nil, COINIT_MULTITHREADED) перед манипуляциями с dbexpress - компонентами, ошибка не пропала
0
Модератор
3488 / 2611 / 741
Регистрация: 19.09.2012
Сообщений: 7,971
23.12.2014, 11:58 6
Текст запроса надо очищать перед добавлением нового.
И св-во qSveden.RecordCount, скорее всего, будет иметь неправильное значение.

Добавлено через 1 минуту
А параметры должны задаваться после добавления нового запроса.
0
2649 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,725
23.12.2014, 12:15 7
Цитата Сообщение от Childeroland Посмотреть сообщение
он мне без особого труда позволяет в другой модуль передать любое количество параметров
Что ж тогда не передал параметром AQuery: TSqlQuery ?
Ведь это сводит на нет концепцию независимости и самодостаточности нити..

Вот ты поймай сначала брейк на строках

Код
with dmSved do // этой
         begin
           if qSveden.Active =  True then // потом этой
и убедись что dmSved и qSveden у тебя не nil - потом продолжим рассуждения о существовании объектов)

Цитата Сообщение от Childeroland Посмотреть сообщение
Добавил CoInitializeEx
Молодец, тем самым ты убрал грабли, которые обязаны были выстрелить следом за текущими)
0
0 / 0 / 1
Регистрация: 29.07.2012
Сообщений: 16
23.12.2014, 12:57  [ТС] 8
Цитата Сообщение от mss Посмотреть сообщение
Что ж тогда не передал параметром AQuery: TSqlQuery ?
Ведь это сводит на нет концепцию независимости и самодостаточности нити..

Вот ты поймай сначала брейк на строках

Код
with dmSved do // этой
         begin
           if qSveden.Active =  True then // потом этой
и убедись что dmSved и qSveden у тебя не nil - потом продолжим рассуждения о существовании объектов)


Молодец, тем самым ты убрал грабли, которые обязаны были выстрелить следом за текущими)
Цитата Сообщение от mss Посмотреть сообщение
Что ж тогда не передал параметром AQuery: TSqlQuery ?
Ведь это сводит на нет концепцию независимости и самодостаточности нити..
Вот тут вообще не понял ничего... Передать параметром query, зачем?

как проверить, что не nil?
Цитата Сообщение от FIL Посмотреть сообщение
Текст запроса надо очищать перед добавлением нового.
И св-во qSveden.RecordCount, скорее всего, будет иметь неправильное значение.
Добавлено через 1 минуту
А параметры должны задаваться после добавления нового запроса.
Очищал, на самом деле, удалил строку по запарке, спасибо за тык носом... Про RecordCount тоже знаю, поэтому, собственно, и не парился с MessageBox, до него всё равно дело не дойдёт, хотя, конечно, исправлю

Добавлено через 16 минут
Делал так:
Delphi
1
if assigned(qSveden) then <действия>
Вероятно вы это имели в виду, действия выполняются, значит, опять таки, прихожу к выводу, что компонент создан
0
2649 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,725
23.12.2014, 13:10 9
Цитата Сообщение от Childeroland Посмотреть сообщение
не понял ничего... Передать параметром query, зачем?
Стремный ты перец)
А зачем тогда ты передаешь параметром PPointerRecord ?
Ведь все по тем же, надо понимать, соображениям: обеспечить независимость кода нити от вызывающего ее окружения ..

Только вот в случае с дейтамодулем и объектом-квериком ты почему-то не обеспечиваешь ту же самую независимость, допуская прямые ссылки на объекты, создаваемые и контролируемые внешним (по отношению к модулю нити) кодом.. А нить-то не должна ничего знать ни о существовании дейтамодуля, ни о факте шлепнутого на него кверика - она должна знать лишь о том что вот с таким-то объектом, переданным параметром (и потому по барабану где и как рожденным), следует работать как с квериком для доступа к такой-то СУБД

А еще круче - рождать и уничтожать этот самый кверик (и все безусловно необходимые для его работы прочие вспомогательные объекты) прямо в контексте самой нити .. Это уже серьезный пилотаж, к коему следует стремиться)

Добавлено через 4 минуты
Цитата Сообщение от Childeroland Посмотреть сообщение
действия выполняются, значит, опять таки, прихожу к выводу, что компонент создан
Охотно верю.
Но кверик-то то у тебя наверняка не самостоятелен - он зависит (явно или неявно) от других клиентских СУБД-объектов: database, session ..
А они у тебя почти наверняка создаются и инициализируются в основном потоке, создавшем дейтамодуль ..
0
0 / 0 / 1
Регистрация: 29.07.2012
Сообщений: 16
23.12.2014, 13:42  [ТС] 10
А еще круче - рождать и уничтожать этот самый кверик (и все безусловно необходимые для его работы прочие вспомогательные объекты) прямо в контексте самой нити .. Это уже серьезный пилотаж, к коему следует стремиться)
Так я и стремлюсь, просто потоки я всегда обходил стороной, а тут решил заняться, уж не годы ими занимаюсь, можно и понять, что не всё сразу даётся. Адекватных объяснений в интернете и в справках не много и в основном по TThread... а указатель на запись я передавал уж точно не из-за желания оградить поток от окружения (хоть, может быть, это и неправильно), а из-за того, что это единственный способ передать параметры в процедуру через поток, который я нашёл...
И нифига я не стрёмный, как будто вы родились с кучей книжек по программированию в голове. Дохожу по мере возможности мозга до всякого рода чудес, чего же ругаться-то?

Добавлено через 12 минут
Ковыряние с режимами отладки показало, что копать надо в параметрах компонента qSveden... пойду копать, всем спасибо за ответы, хоть одна тема прошла в оживлённом диалоге
0
2649 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,725
23.12.2014, 13:50 11
Цитата Сообщение от Childeroland Посмотреть сообщение
это единственный способ передать параметры в процедуру через поток, который я нашёл
Странно что ты нашел способ передать кверик через глобальную переменную с дейтамодулем и не нашел тоже самое для записи с параметрами..

Что мешало объавить в ДМ переменную типа запись и обратиться к ней из модуля нити, подобно тому как ты обратился к кверику ? Ничто.. Однако запись ты почему-то передал параметром по ссылке, что близко к правильному решению, в то время как к кверику почему-то лезешь напрямую через ДМ ..

Ничто же, к примеру, не мешало в записи, адрес которой ты передаешь параметром, завести еще одно поле и скопировать туда ссылку на кверик, верно ?

Цитата Сообщение от Childeroland Посмотреть сообщение
нифига я не стрёмный
Ну как же не стремный, если в твоих рассуждениях отсутствует очевидная логика ?)
Код-то чей-то не грех сдувать - хуже не думать над сдутым и не вникать в него)

Добавлено через 5 минут
создай кверик прямо в нити - проще жить будет

Код
CoInitializeEx ..
try
  MyQuery := TSQLQuery.Create(nil);
  try
   .. здесь мордуй свой кверик как хочешь ..
  finally
    MyQuery.Free;
  end;
finally
  CoUninitialize..
end;
0
0 / 0 / 1
Регистрация: 29.07.2012
Сообщений: 16
23.12.2014, 14:29  [ТС] 12
создай кверик прямо в нити - проще жить будет

Код Code
1
2
3
4
5
6
7
8
9
10
11
CoInitializeEx ..
try
MyQuery := TSQLQuery.Create(nil);
try
.. здесь мордуй свой кверик как хочешь ..
finally
MyQuery.Free;
end;
finally
CoUninitialize..
end;
Обязательно попробую
Код я на ходу, можно сказать, переделываю, изначально там и дата-модуля не было, добавил позднее, для удобства, вот и не догадался в него запись засунуть... Задач полно, а времени нет, я же не только этим занимаюсь, не всегда всё сразу замечаешь... Я ещё этот код на несколько раз перекрою наверняка...
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
23.12.2014, 14:29
Помогаю со студенческими работами здесь

Access violation при повторном вызове компонента
Lazarus IDE v1.0.12 fpc 2.6.2 Ubuntu 13.10 i386 Создал визуальный компонент на основе TTreeView...

Access Violation при TClientDataSet.Open
Всем доброго времени суток. Почти впал в отчаяние....... И так, имеется старый проект написанный...

Access Violation при работе потока
var Stream:TStringStream; //поток List1: TStringList; // для загрузки из...

InnoSetup Access Violation при вызове ф-ции из dll c wchart* параметрами
Версия InnoSetup 5.6.1 u Есть DLL собранная на C/C++ в MSVC2015. test.h #ifdef TEST_LIBRARY...


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

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru