Передача интерфейса между потоками
От: Osi2 Украина  
Дата: 18.04.03 10:30
Оценка:
продожение, начало см
Автор:
Дата: 13.04.03



Ситуация: у меня есть главный STA поток, пул потоков-worker'ов, а также один поток, который считывает новых пользователей и создает для них ADO Conenctions. Все эти потоки создаются из main STA. В главном потоке я набиваю атрибуты объекта и ставлю этот объект-задание в очередь для обработки каким-то потоком из пула. Первый свободный поток берет этот объект для обработки.

Объекты Connection для существующих пользователей создаются в main STA потоке, для новых — в другом, отдельном потоке. Эти объекты передаются между потоками в глобальной переменной m_UserCalendars типа typedef map<CString,_CalendarPaths> UserCalendars;


1. код добавления объекта в глобальн. переменную:


bool CCreateAppointment::SetUserCalendars(const CString &Email)
{    
    _ConnectionPtr m_Connection(__uuidof(Connection));
    _CalendarPaths* calendarPaths = new _CalendarPaths();

    if (!ConnectToMailbox(m_aMailBox,"MAILTO:" + Email)) return false;
    _bstr_t bstrURLItem = m_aMailBox->Calendar;

    m_Connection->Provider = "ExOLEDB.DataSource";
    m_Connection->Open(bstrURLItem,bstr_t(),bstr_t(),-1);
    DWORD dwCookie;

    HRESULT hRes = CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER,
                                     IID_IGlobalInterfaceTable, (LPVOID*)&pGIT);

    _ASSERT(SUCCEEDED(hRes) && pGIT);
    
 
    // store interface in GIT
    hRes = pGIT->RegisterInterfaceInGlobal(m_Connection, IID__Connection, &dwCookie);
    
    calendarPaths->CalendarURL = bstrURLItem;
    calendarPaths->connectionCookie = dwCookie;

    m_UserCalendars.insert(pair<CString,_CalendarPaths>(Email,*calendarPaths));
    
    delete calendarPaths;
    return true;
}



2. код считывания из глобальн. переменной.


bool CCreateAppointment::GetUserCalendar(const CString& Email,_CalendarPaths* CalendPaths)
{
    map<CString,_CalendarPaths>::iterator userCalendarIt;

    // searches connections in the map by user email, if there nothing was found,
    // tries to connect to mailboxes

    for (int i=0; i<2; i++)
    {
        userCalendarIt = m_UserCalendars.find(Email);
        if (userCalendarIt != m_UserCalendars.end())
        {
            *CalendPaths = (*userCalendarIt).second;
            return true;
        }
        else
            SetUserCalendars(Email);
        
    }
    TRACER.Print(LOG_ERROR, _T("CCreateAppointment::GetUserCalendar, obtaining the connection to the users mailbox failed"));
    return false;
}

+ функция 

_ConnectionPtr _CalendarPaths::getConnection()
{
    DWORD dwCookie = _CalendarPaths::connectionCookie;

    _ConnectionPtr pConnection = NULL;

    // get proxy to interface from GIT

    HRESULT hRes = pGIT->GetInterfaceFromGlobal(dwCookie, IID__Connection, (LPVOID*)&pConnection);

    if (pConnection == NULL) TRACER.Print(LOG_ERROR,_T("_CalendarPaths::getConnection(), couldn't get the Connection"));

    return pConnection;
}


все потоки выполняются в одном процессе.

Проблема в том, что когда я пытаюсь взять Connection внутри какого-то worker thread, то выдается ошибка:

The application called an interface that was marshalled for a different thread

объясните пожалста, из-за чего может быть ошибка? я думал что интерфейс, записанный в GIT потом можно будет прочитать из любого потока, но .. что-то не так. Еще, если в программе не делать пул потоков, а передавать Connection с помощью GIT в главный STA, то все работает нормально.
Re: Передача интерфейса между потоками
От: Tom Россия http://www.RSDN.ru
Дата: 18.04.03 11:23
Оценка:
CoInitialize() для каждого потока вызываеш?
... << RSDN@Home 1.0 beta 6a >>
Народная мудрось
всем все никому ничего(с).
Re: Передача интерфейса между потоками
От: Clickmaker Россия http://relaxander.webest.net/
Дата: 18.04.03 12:25
Оценка:
Здравствуйте, Osi2, Вы писали:

O>продожение, начало см
Автор:
Дата: 13.04.03

O>

O>Ситуация: у меня есть главный STA поток, пул потоков-worker'ов, а также один поток, который считывает новых пользователей и создает для них ADO Conenctions. Все эти потоки создаются из main STA. В главном потоке я набиваю атрибуты объекта и ставлю этот объект-задание в очередь для обработки каким-то потоком из пула. Первый свободный поток берет этот объект для обработки.


O>Объекты Connection для существующих пользователей создаются в main STA потоке, для новых — в другом, отдельном потоке. Эти объекты передаются между потоками в глобальной переменной m_UserCalendars типа typedef map<CString,_CalendarPaths> UserCalendars;



CoMarshalInterThreadInterfaceInStream / CoGetInterfaceAndReleaseStream
Re[2]: Передача интерфейса между потоками
От: Osi2 Украина  
Дата: 18.04.03 14:14
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>CoInitialize() для каждого потока вызываеш?


да, абсолютно в каждом потоке.
Re[2]: Передача интерфейса между потоками
От: Osi2 Украина  
Дата: 18.04.03 14:24
Оценка:
Здравствуйте, Clickmaker, Вы писали:

C>Здравствуйте, Osi2, Вы писали:


O>продожение, начало см
Автор:
Дата: 13.04.03

O>

O>Ситуация: у меня есть главный STA поток, пул потоков-worker'ов, а также один поток, который считывает новых пользователей и создает для них ADO Conenctions. Все эти потоки создаются из main STA. В главном потоке я набиваю атрибуты объекта и ставлю этот объект-задание в очередь для обработки каким-то потоком из пула. Первый свободный поток берет этот объект для обработки.


O>Объекты Connection для существующих пользователей создаются в main STA потоке, для новых — в другом, отдельном потоке. Эти объекты передаются между потоками в глобальной переменной m_UserCalendars типа typedef map<CString,_CalendarPaths> UserCalendars;



C>CoMarshalInterThreadInterfaceInStream / CoGetInterfaceAndReleaseStream


я специально не стал использовать эти функции, т.к. после вызова CoGetInterfaceAndReleaseStream, объект IStream освобождается, а мне чтобы объект Connection можно было бы получать много раз, на протыжении жизни всего процесса. GlobalInterfaceTable как раз и подходит до этого, но где-то есть ошибка и я не пойму где именно.
Re: Передача интерфейса между потоками
От: Ivan Россия www.rsdn.ru
Дата: 18.04.03 15:53
Оценка:
Здравствуйте, Osi2, Вы писали:

Попробуй в этом месте создавать GIT:
вместо
O> HRESULT hRes = pGIT->GetInterfaceFromGlobal(dwCookie, IID__Connection, (LPVOID*)&pConnection);

    HRESULT hRes = CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER,
                                     IID_IGlobalInterfaceTable, (LPVOID*)&pGIT);


P.S. Если не поможет, то напиши точно — кто возвращает ошибку — обращение к GIT и обращение к интерфейсу, который ты вытаскиваешь из GIT
Re[2]: Передача интерфейса между потоками
От: Osi2 Украина  
Дата: 18.04.03 16:14
Оценка:
Здравствуйте, Ivan, Вы писали:

I>Здравствуйте, Osi2, Вы писали:


I>Попробуй в этом месте создавать GIT:

I>вместо
O> HRESULT hRes = pGIT->GetInterfaceFromGlobal(dwCookie, IID__Connection, (LPVOID*)&pConnection);

I>
I>    HRESULT hRes = CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER,
I>                                     IID_IGlobalInterfaceTable, (LPVOID*)&pGIT);
I>


I>P.S. Если не поможет, то напиши точно — кто возвращает ошибку — обращение к GIT и обращение к интерфейсу, который ты вытаскиваешь из GIT


Если я правильно понял, то ты предлагаешь в функции где получаю интерфейс, предварительно еще раз проинициализировать GIT.
до этого, и сейчас ошибку вызывало только обращение к интерфейсу. C GIT все в порядке.

исправленный код:


_ConnectionPtr _CalendarPaths::getConnection()
{
    DWORD dwCookie = _CalendarPaths::connectionCookie;

    _ConnectionPtr pConnection = NULL;

    // get proxy to interface from GIT

    HRESULT hRes = CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER,
                                     IID_IGlobalInterfaceTable, (LPVOID*)&pGIT);

    TRACER.Print(LOG_INFO,_T("result of getting the GID: %d"),hRes);

    hRes = pGIT->GetInterfaceFromGlobal(dwCookie, IID__Connection, (LPVOID*)&pConnection);

    TRACER.Print(LOG_INFO,_T("result of getting the connection: %d"),hRes);
    if (pConnection == NULL) TRACER.Print(LOG_ERROR,_T("_CalendarPaths::getConnection(), couldn't get the Connection"));

    return pConnection;
}


результат:


$$ INFO: result of getting the GID: 0
$$ INFO: result of getting the connection: 0
Re[3]: Передача интерфейса между потоками
От: Osi2 Украина  
Дата: 21.04.03 19:33
Оценка:
Здравствуйте, Osi2, Вы писали:


Пробовал инициализировать GIT в при каждом обращении к ней (запись/считывание) и один раз вначале выполнения — результат один и тот же.

I> HRESULT hRes = CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER,

I> IID_IGlobalInterfaceTable, (LPVOID*)&pGIT);

O>$$ INFO: result of getting the GID: 0

O>$$ INFO: result of getting the connection: 0

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

Я просто уверен, что где-то наступил на грабли.

напишу еще разок, самому станет понятнее:
есть нт сервис, вызывающий у dll метод create. Dll — apartmentthreaded.
там создаю GIT, заношу туда какие-то данные, создаю поток, в нем заношу дополнительные Connection для новых юзеров. В самом create создаю сокет.
при поступлении на него данных (да, неправильно это, но у меня CSocket и исправлять уже некогда) считываю их и создаю новый поток. В этом потоке беру GIT, считываю из нее мои Connectionы, и... — error.
при создании потоков везде указываю CoInitialize.
что не правильно?

А нельзя ли создать обыкновенный класс с одим атрибутом типа Connection и его передавать? Структуру я уже так поборол.
Re[4]: Может есть еще идеи
От: Osi2 Украина  
Дата: 22.04.03 12:40
Оценка:
Здравствуйте, Osi2, Вы писали:

Уже все перепробовал. Eсть какие-нибудь другие варианты, может похожее что-то. Или весь код может прислать?
просто решение нужно очень быстро, а я до этого с этим не работал.
Re[5]: Может есть еще идеи
От: Ivan Россия www.rsdn.ru
Дата: 22.04.03 12:52
Оценка:
Здравствуйте, Osi2, Вы писали:

O>Здравствуйте, Osi2, Вы писали:


O>Уже все перепробовал. Eсть какие-нибудь другие варианты, может похожее что-то. Или весь код может прислать?

O>просто решение нужно очень быстро, а я до этого с этим не работал.

На чем ты получаешь ошибку ? При вызове любого метода у интерфейса Connection ?
Re[6]: Может есть еще идеи
От: Osi2 Украина  
Дата: 22.04.03 12:54
Оценка:
Здравствуйте, Ivan, Вы писали:

I>Здравствуйте, Osi2, Вы писали:


O>Здравствуйте, Osi2, Вы писали:


O>Уже все перепробовал. Eсть какие-нибудь другие варианты, может похожее что-то. Или весь код может прислать?

O>просто решение нужно очень быстро, а я до этого с этим не работал.

I>На чем ты получаешь ошибку ? При вызове любого метода у интерфейса Connection ?




нет, при использовании его как параметра, вот например здесь:

hr = pRecordset->Open(variant_t(sQuery1+sQuery2),variant_t((IDispatch*)m_Connection, true),
adOpenUnspecified,
adLockUnspecified,
-1);
Re[7]: Может есть еще идеи
От: Ivan Россия www.rsdn.ru
Дата: 22.04.03 12:58
Оценка: 2 (1)
Здравствуйте, Osi2, Вы писали:

O>нет, при использовании его как параметра, вот например здесь:

O> hr = pRecordset->Open(variant_t(sQuery1+sQuery2),variant_t((IDispatch*)m_Connection, true),
O> adOpenUnspecified,
O> adLockUnspecified,
O>

А ты уверен, что проблема не в самом указателе pRecordset ? Попробуй вообще вместо m_Connection 0 передать, пропадет ошибка(в смысле на другую заменится ) ?
Re[8]: Может есть еще идеи
От: Osi2 Украина  
Дата: 22.04.03 13:08
Оценка:
Здравствуйте, Ivan, Вы писали:

I>Здравствуйте, Osi2, Вы писали:


O>нет, при использовании его как параметра, вот например здесь:

O> hr = pRecordset->Open(variant_t(sQuery1+sQuery2),variant_t((IDispatch*)m_Connection, true),
O> adOpenUnspecified,
O> adLockUnspecified,
O>

I>А ты уверен, что проблема не в самом указателе pRecordset ? Попробуй вообще вместо m_Connection 0 передать, пропадет ошибка(в смысле на другую заменится ) ?



вставил variant_t() на его место.
да ошибка, заменилась

## ERROR: CCreateAppointment::SelectAppointments, Error when opening recordset: Unknown error 0x800A0BB9, hr: 0

выходит что все-таки в Connection'е дело.
Re[9]: Может есть еще идеи
От: Ivan Россия www.rsdn.ru
Дата: 22.04.03 13:19
Оценка:
Здравствуйте, Osi2, Вы писали:

O>Здравствуйте, Ivan, Вы писали:


O>выходит что все-таки в Connection'е дело.

Попробуй еще убрать (временно) GIT и создавать Connection непосредтсвенно перед использованием в recordset
Re[10]: Может есть еще идеи
От: Osi2 Украина  
Дата: 22.04.03 13:29
Оценка:
Здравствуйте, Ivan, Вы писали:

I>Здравствуйте, Osi2, Вы писали:


O>Здравствуйте, Ivan, Вы писали:


O>выходит что все-таки в Connection'е дело.

I>Попробуй еще убрать (временно) GIT и создавать Connection непосредтсвенно перед использованием в recordset

бред какой-то
стало еще более запутанней:

## ERROR: CCreateAppointment::SelectAppointments, error: Unspecified error, hr: 0
Re[11]: Может есть еще идеи
От: Osi2 Украина  
Дата: 22.04.03 13:31
Оценка:
Здравствуйте, Osi2, Вы писали:

O>Здравствуйте, Ivan, Вы писали:


I>Здравствуйте, Osi2, Вы писали:


O>Здравствуйте, Ivan, Вы писали:


O>выходит что все-таки в Connection'е дело.

I>Попробуй еще убрать (временно) GIT и создавать Connection непосредтсвенно перед использованием в recordset

O>бред какой-то

O>стало еще более запутанней:

O>## ERROR: CCreateAppointment::SelectAppointments, error: Unspecified error, hr: 0


это была ошибка открытия Connection'a
здесь
m_Connection->Open(bstrURLItem,_bstr_t(),_bstr_t(),-1);
Re[11]: Может есть еще идеи
От: Ivan Россия www.rsdn.ru
Дата: 22.04.03 13:33
Оценка:
Здравствуйте, Osi2, Вы писали:

O>бред какой-то

O>стало еще более запутанней:

Действительно, странно
Re[12]: Может есть еще идеи
От: Ivan Россия www.rsdn.ru
Дата: 22.04.03 13:35
Оценка:
Здравствуйте, Osi2, Вы писали:

O>это была ошибка открытия Connection'a

O>здесь
O>m_Connection->Open(bstrURLItem,_bstr_t(),_bstr_t(),-1);

А что за апартмент у этого потока ?
Re[13]: Может есть еще идеи
От: Osi2 Украина  
Дата: 22.04.03 13:41
Оценка:
Здравствуйте, Ivan, Вы писали:

I>Здравствуйте, Osi2, Вы писали:


O>это была ошибка открытия Connection'a

O>здесь
O>m_Connection->Open(bstrURLItem,_bstr_t(),_bstr_t(),-1);

I>А что за апартмент у этого потока ?


У него — STA.
вот:

DWORD WINAPI ProcessRequest_Thread(LPVOID lpParam)
{
TRACE_FUNCTION_IN(_T("ProcessMainThread"));
HRESULT hr = CoInitialize(NULL);
TRACER.Print(LOG_INFO,_T("ProcessMainThread init: %d"),hr);

CSockParams* sockParams = (CSockParams*)lpParam;

CCreateAppointment* m_CreateAppointment = new CCreateAppointment();
m_CreateAppointment->ManageAppointment(*sockParams);
delete sockParams;
delete m_CreateAppointment;

CoUninitialize();
return 1;
}
Re[14]: Может есть еще идеи
От: Ivan Россия www.rsdn.ru
Дата: 22.04.03 13:43
Оценка: 2 (1)
Здравствуйте, Osi2, Вы писали:

Надо разобраться, почему открытие соединения вовзаращает E_FAIL, сейчас маршалинг явно ни при чем
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.