XPCOM C ++ многопоточность и обратный вызов JavaScript

В версии XULRunner ниже 12.0 это работает, но когда я пытаюсь перенести его на версию 12.0 или выше, происходит сбой приложения.
Основная причина в том, что в SDK v12 или новее разработчики удаляют прокси-объекты для компонентов xpcom и рекомендуют заменить их
оборачивая объекты с помощью nsRunnable / nsIRunnable и направляя вызов в основной поток функцией NS_DispatchToMainThread (щелкните Вот)

Я создал коннектор БД, который является асинхронным и соединяется с основным потоком с помощью обратных вызовов.
Использование: XULRunner v6, портирование на XULRunner v17 или выше



//nsIDBCallback.idl
[scriptable, function, uuid(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)]
interface nsIDBCallback : nsISupports {
void onInfo(in long phase, in long status, in string info);
}



//nsDBService.h, it is XPCOM component
class nsDBService : public nsIDBService, nsIRunnable
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
NS_DECL_NSIDBSERVICE

private:
std::vector<nsIThread*>     threads;
std::vector<nsIDBCallback*> callbacks;
std::vector<const char*>    sqls;

nsIThread* makeNewThread();
void       runOperationIfNotBussy();

public:
NS_IMETHODIMP Query(const char *sql, nsIDBCallback *callback);
}



//nsDBService.cpp
// adding query and other data to buffers,
// it's thread safe, there are used mutex's
NS_IMETHODIMP nsDBService::Query(const char *sql, nsIDBCallback *callback)
{
callbacks.push_back(callback);
sqls     .push_back(sql);
threads  .push_back( makeNewThread() );

//run added operation if db driver is free,
//if driver is bussy then invocation is in buffer and need to wait
runOperationIfNotBussy();

return NS_OK;
}

void nsDBService::runOperationIfNotBussy()
{
//some conditions, test's etc.

//run first operation on list
// RUNNING A THREAD, still ok
if(...) threads.front()->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
}

//if this method is used by another thread+db query,
//then other operations can't run and need to wait
//operations are stored and supported like fifo
NS_IMETHODIMP nsDBService::Run(void)
{
//some other operations
//real db operations in background

int32_t phase = 3; //endphase
int32_t code  = 0; //ok
const char *msg = "OK";

nsIDBCallback *callback = callbacks.pop();
//wrapping callback function with runnable interface
nsIRunnable   *runCallback = new nsResultCallback(callback,
phase,
code,
msg);
//routing event to main thread
NS_DispatchToMainThread(runCallback, NS_DISPATCH_NORMAL);

runOperationIfNotBussy();
}



//nsResultCallback.h
class nsResultCallback: public nsRunnable
{
public:
NS_DECL_ISUPPORTS
public:
NS_DECL_NSIRUNNABLE

private:
nsIDBCallback* callback;
int32_t        resPhase;
int32_t        resStatus;
const char*    resMessage;

public:
nsResultCallback(nsIDBCallback* callback,
int32_t phase,
int32_t status,
const std::string &message)
: callback(callback),
resPhase(phase),
resStatus(status),
resMessage(c_str_clone(message.c_str())) {};
~nsResultCallback();

};



//nsResultCallback.cpp
NS_IMETHODIMP nsResultCallback::Run(void)
{
nsresult rv = NS_ERROR_FAILURE;
try
{
// APP HANDS AND CRUSH !
if(this->callback) this->callback->OnInfo(resPhase, resStatus, resMessage);
}
catch(...)
{
rv = NS_ERROR_UNEXPECTED;
ERRF("nsBackpack::Run call method OnInfo from callback failed");
}
return rv;
}

ВЫЗОВ



// *.js
nsDBService.query("SELECT * FROM t", function(phase, code, mes) {
//some UI actions or others db queries
});

Проблема:

Приложение зависает и падает, когда выполнение кода выглядит следующим образом:



nsDBService::Query //main thread ok
nsDBService::runOperationIfNotBussy //main thread
nsDBService::threads.front()->Dispatch //run bg thread
nsDBService:Run //bg thread
NS_DispatchToMainThread //main thread
nsResultCallback::Run //main thread
nsIDBCallback::OnInfo //main thread, crash

Если выполнение кода выглядит так, все в порядке:

                                                                                                       

nsDBService::Query //main thread ok
NS_DispatchToMainThread //main thread
nsResultCallback::Run //main thread
nsIDBCallback::OnInfo //main thread ok

[/ NOEDIT]

Вопрос:

Когда nsIDBCallback вызывается из NS_DispatchToMainThread и NS_DispatchToMainThread вызывается из другого потока, а не из основного потока приложения, то выполнение завершается неудачно, чего мне не хватает, не понимаете? Или каков другой подход для фоновых задач?

7

Решение

Невозможно воспроизвести, поскольку вы не предоставили отдельный, полный пример, поэтому вместо этого приведем некоторые замечания:

Первое, что я заметил, это перекрестный доступ std::vector, Вы написали что-то о мьютексах в комментариях, так что это может быть хорошо.

Что это конечно неправильно, хранит сырые указатели на nsIDBCallback, Объекты XPCOM пересчитываются. Так что, как только ваш Query метод возвращает, базовый объект может быть deleted, если нет других ссылок на него, оставляя висячий указатель в вашем векторе. я считать это то, что здесь происходит!
Вы должны сохранить объект живым, пока с ним не закончится нить, предпочтительно, поместив его в nsCOMPtr<nsIDBCallback> где-то, например в nsCOMPArray<nsIDBCallback>.

PS: Оказывается, это довольно старый вопрос, который я пропустил ... Так что извините за задержка отвечая на это: p

1

Другие решения

Других решений пока нет ...

По вопросам рекламы [email protected]