1 (изменено: vo1ty, 2012-11-30 00:43:26)

Тема: JScript: Многопоточность: [DynamicWrapperX] WINAPI и CreateTheard

Здравствуйте! Уже не раз работал с RegisterCallback (DynamicWrapperX), создавая клавиатурные хуки и даже регистрируя классы окон (для всего этого нужно указывать callback-функции), но с потоками проблемы.

DX = new ActiveXObject("DynamicWrapperX");
DX.Register("kernel32", "CreateThread", "i=puppup", "r=h"); // на параметры не ругается, хотя, возможно, я что-то неверно указал
TProc = function(pp)
{
  // Этот поток должен выполняться "параллельно", не зависимо
  WScript.Echo('thread created');
  // Вывод в качестве примера, естественно.
  return 0;
}
pTProc = DX.RegisterCallback(TProc, "i=p", "r=p"); // также не исключаю, что что-то неверно, но ошибки не выползают.
thr = DX.CreateThread(0, 0, pTProc, 0, 0, 0);
WScript.Echo(thr);
// Выводит целое число > 0. Если верить MSDN, это значит, что поток создан без ошибок.
// В это же время, по идее, должно выводиться сообщение 'thread created', но ничего нет.

Что я не так делаю? И, может, не стоило париться с велосипедом, и есть более доступные способы запустить два потока одновременно?
Пусть вас не пугает, что я использую CreateThread, указывая только третий параметр. Аналогичная программа в C++ работает без каких-либо нареканий. Если нужно, могу дать пример.

2

Re: JScript: Многопоточность: [DynamicWrapperX] WINAPI и CreateTheard

Да, в другом потоке выполнить функцию скрипта не удаётся. Причины тут где-то глубоко, сам я до них не докапывался. Думаю, chessman имеет что сказать по данной проблеме, судя по этому сообщению. Если он заглянет в эту тему, то, возможно, пояснит подробнее.

3

Re: JScript: Многопоточность: [DynamicWrapperX] WINAPI и CreateTheard

В общем, мне удалось вызвать функцию скрипта из другого потока, но толку от этого нет, т.к. скрипт не выполняется параллельно, а ждёт завершения этой функции.

4

Re: JScript: Многопоточность: [DynamicWrapperX] WINAPI и CreateTheard

Есть пока что одно нехорошее решение.

doc = new ActiveXObject("htmlfile");
doc.parentWindow.setTimeout(function() {
  WScript.Echo('this is thread!');
}, 0);

Не нравится оно мне тем, что приходится загружать ещё и htmlfile, не говоря уж о том, что, ВОЗМОЖНО (хотя я сомневаюсь), работа этого скрипта будет зависеть от настроек IE. Надеюсь, что его нельзя заблокировать.

5

Re: JScript: Многопоточность: [DynamicWrapperX] WINAPI и CreateTheard

vo1ty пишет:

Есть пока что одно нехорошее решение.

На самом деле поток там один и тот же. Это можно проверить, посмотрев через API GetWindowThreadProcessId, каким потоком создаются диалоговые окна в этом примере:


doc = new ActiveXObject("htmlfile");
doc.parentWindow.setTimeout(function() {
  WScript.Echo('this is thread!');
}, 0);

WScript.Echo("The end.")

Посмотреть можно, например, скриптом AutoHotkey:


F11::
    hWnd := WinExist("A")
    ThreadID := DllCall("user32.dll\GetWindowThreadProcessId"
                            , "Ptr", hWnd, "Ptr", 0)
    MsgBox, %ThreadID%
Return

Насколько я понимаю суть проблемы, функцию скрипта можно вызвать из другого потока, но выполняться она будет в своём, а не в том, который её вызвал. Код скрипта, видимо, выполняется в однопоточном апартменте (single-threaded apartment). Поэтому вызовы к его объектам (а функция — это объект) из других потоков должны идти не напрямую, а через прокси. Прокси создаётся в вызывающем потоке при маршалинге в него указателя на интерфейс вызываемого объекта. Вызывающий код получает указатель на этот прокси, а не на оригинальный объект. Сам прокси также не вызывает методы объекта напрямую, а посылает оконное сообщение в вызываемый поток. И уже там по этому сообщению вызывается метод объекта, т.е. работает он в своём потоке. Так что параллельности не получается.

Если просто использовать в другом потоке указатель на объект функции, без маршалинга, и попробовать вызвать функцию напрямую, то вернётся код ошибки. Не знаю, есть ли там какая-то защита от такого вызова или просто функции нужно что-то, хранящееся в локальной памяти потока (TLS), и она этого в другом потоке не находит. Указатель на объект DynamicWrapperX, к примеру, можно передать в другой поток и вызвать оттуда напрямую его метод, и там выполнение действительно пойдёт параллельно (другое дело, что он на это не рассчитан). С объектом функции это не проходит.

6

Re: JScript: Многопоточность: [DynamicWrapperX] WINAPI и CreateTheard

YMP пишет:

В общем, мне удалось вызвать функцию скрипта из другого потока, но толку от этого нет, т.к. скрипт не выполняется параллельно, а ждёт завершения этой функции.

Юрий, поделись, как сделал.

7

Re: JScript: Многопоточность: [DynamicWrapperX] WINAPI и CreateTheard

chessman
Я имел в виду, что поэкспериментировал с кодом внутри Dynwrapx. Добавил в RegisterCallback ещё один параметр, по которому она помещала в структуру Callback вместо указателя на объект функции указатель на IStream, полученный от CoMarshalInterThreadInterfaceInStream. Добавил метод NewThread, который запускал новый поток со встроенной функции, которая в свою очередь вызывала CoInitialize и CoGetInterfaceAndReleaseStream и заменяла в структуре Callback указатель на IStream указателем на прокси. После этого вызовы из нового потока по указателю, возвращаемому RegisterCallback, работают, запускается функция скрипта, но, скажем, вот такой цикл


For i=0 to 7
    DX.Beep 800, 100
    WSH.Sleep 1000
Next

при этом останавливается и ждёт, пока я не закрою диалоговое окно, выведенное функцией, т.е. видно, что параллельного выполнения нет. Функция просто вклинивается между командами скрипта. Интересно, что если вторую команду цикла реализовать как DX.Sleep 1000, функция цикл не прерывает. Видимо, при вызове WSH.Sleep проверяется очередь сообщений и обрабатывается сообщение, полученное от прокси, а Dynwrapx, конечно, этого не делает.

8 (изменено: chessman, 2012-12-03 14:21:13)

Re: JScript: Многопоточность: [DynamicWrapperX] WINAPI и CreateTheard

YMP пишет:

...что поэкспериментировал с кодом внутри Dynwrapx.

Да, я это имел ввиду.
Знакомая техника, я что-то подобное использовал в борьбе с Microsoft Outllook , но все равно интересно .
Спс.

Скорее всего можно в новом потоке создавать новый объект скрипта и скармливать ему кусок кода, вот тогда наверное заработает параллельность.
Но это просто мысли вслух.

9

Re: JScript: Многопоточность: [DynamicWrapperX] WINAPI и CreateTheard

chessman пишет:

Скорее всего можно в новом потоке создавать новый объект скрипта и скармливать ему кусок кода, вот тогда наверное заработает параллельность.
Но это просто мысли вслух.

Может, свой скрипт-контрол соорудить многопоточный? Как-то я читал, что требуется от скрипт-хоста — вроде не так много, какие-то два или три интерфейса. Всю работу ведь по идее движок будет делать. Интересно было бы попробовать.

10

Re: JScript: Многопоточность: [DynamicWrapperX] WINAPI и CreateTheard

Если стоит IE8 и выше, то доступен HTML 5-объект Worker. Стандартными средствами добиться многопоточности вряд ли выйдет. У меня получилось только псевдомногопоточности благодаря связки между процессами через COM-связь.

11

Re: JScript: Многопоточность: [DynamicWrapperX] WINAPI и CreateTheard

Сами движки JScript и VBScript многопоточность поддерживают, судя по тому, что их потоковая модель обозначена в реестре как "Both". Так что дело за хостом. У объектов Windows Script Host — Shell и Network — потоковая модель "Apartment", т.е. однопоточная, так что, видимо, WSH потоки не поддерживает.