I have a bunch of small lookup tables in my database. It would be efficient to load them into local tables before processing the large table. Prefer to do this rather than a complicated join on the server-side and a new metadata type declaration in the middle layer.
So then this code demonstrates my complete lack of any understanding of how concurrency is supposed to work:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
concurrencyFlags = 0;
context.Load<Priorite>(context.GetPrioritiesQuery(), LoadBehavior.RefreshCurrent, prioritiesHaveBeenLoaded, null);
context.Load<Projet>(context.GetProjectsQuery(), LoadBehavior.RefreshCurrent, projectsHaveBeenLoaded, null);
context.Load<TypeTicket>(context.GetTypeTicketsQuery(), LoadBehavior.RefreshCurrent, typeTicketsHaveBeenLoaded, null);
context.Load<Ticket>(context.GetOpenTicketsQuery(), LoadBehavior.RefreshCurrent, ticketsHaveBeenLoaded, null);
while (concurrencyFlags != everythingLoadedNow) System.Threading.Thread.Sleep(1000);
proceedSingleThreadedFromHere();
}
What is the proper way of doing this? Many thanks,
Because you block on the UI thread, the loading may not happen. Also, your UI becomes unresponsive. Instead, you should make the concurrencyFlags a field that can be used when the loads complete.
private int _concurrencyFlags;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
_concurrencyFlags++;
context.Load<Priorite>(context.GetPrioritiesQuery(), LoadBehavior.RefreshCurrent, prioritiesHaveBeenLoaded, null);
_concurrencyFlags++;
context.Load<Projet>(context.GetProjectsQuery(), LoadBehavior.RefreshCurrent, projectsHaveBeenLoaded, null);
_concurrencyFlags++;
context.Load<TypeTicket>(context.GetTypeTicketsQuery(), LoadBehavior.RefreshCurrent, typeTicketsHaveBeenLoaded, null);
_concurrencyFlags++;
context.Load<Ticket>(context.GetOpenTicketsQuery(), LoadBehavior.RefreshCurrent, ticketsHaveBeenLoaded, null);
}
In each method, call proceedSingleThreadedFromHere():
private void prioritiesHaveBeenLoaded(...)
{
// Do work
_concurrencyFlags--;
proceedSingleThreadedFromHere();
}
Check for the value of the _concurrencyFlags before proceeding:
private void proceedSingleThreadedFromHere()
{
if (_concurrencyFlags > 0) return;
// Do work
}
This isn't thread-safe, but WCF RIA calls back on the UI thread by default. So in theory it should be good enough for a prototype.
Related
I have an Single-document Interface(SDI) Microsoft Foundation Class(MFC) app that has to load a big document file (takes about 2 minutes). For that reason, my app stays unresponsive while I am opening the document.
However, I would like my app to be responsive while opening the document. The problem is that, if I try to load my document on a thread, my OnopenDocument function (in my doc) will return before I actually open the document:
BOOL CmodguiDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
start_tread(_open_doc); // just an example
return TRUE; // Will return before the document will actually be open
}
How can I do this to be non-locking but only returning after the document is actually open? Or how can I at least make my app responsive while I am loading the document?
Thanks
Returning after the thread has been created is OK. You should define a state for the document such as loading and loaded. When you start the thread the state should be loading. The view(s) should look at the state and display accordingly. When the thread has finished loading the document it should post a message to the document. In the handler, set the state to loaded and call UpdateAllViews() to give the views the chance to update with the new document data.
Example: This will print "loading" while the doc is loading and "loaded" and loaded after it finished in the view.
In resource.h:
#define IDD_NotifyDocumentFinished 101
In the document header:
public:
enum DocState
{
None,
Failed,
Loading,
Loaded
};
DocState GetDocState() const {return m_state;}
private:
DocState m_state;
void StartLoading();
In the document implementation:
BOOL CMFCDocViewAsyncDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if(!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
m_state = Loading;
StartLoading();
return TRUE;
}
UINT LongRunningFunction(LPVOID param)
{
Sleep(3000);
HWND hWnd = AfxGetApp()->m_pMainWnd->GetSafeHwnd();
NMHDR hdr = {hWnd, IDD_NotifyDocumentFinished, 0};
::SendMessage(hWnd, WM_NOTIFY, 0, reinterpret_cast<LPARAM>(&hdr));
return 0;
}
void CMFCDocViewAsyncDoc::StartLoading()
{
AfxBeginThread(&LongRunningFunction, nullptr);
}
BOOL CMFCDocViewAsyncDoc::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
if(HIWORD(nCode) == WM_NOTIFY)
{
WORD wCode = LOWORD(nCode);
AFX_NOTIFY * notify = reinterpret_cast<AFX_NOTIFY*>(pExtra);
if(notify->pNMHDR->idFrom == IDD_NotifyDocumentFinished)
{
m_state = Loaded;
UpdateAllViews(nullptr);
}
}
return TRUE;
}
In the view:
void CMFCDocViewAsyncView::OnDraw(CDC* pDC)
{
CMFCDocViewAsyncDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
CMFCDocViewAsyncDoc::DocState state = pDoc->GetDocState();
CString sstate;
switch(state)
{
case CMFCDocViewAsyncDoc::None:
sstate = "None";
break;
case CMFCDocViewAsyncDoc::Failed:
sstate = "Failed";
break;
case CMFCDocViewAsyncDoc::Loading:
sstate = "Loading";
break;
case CMFCDocViewAsyncDoc::Loaded:
sstate = "Loaded";
break;
}
pDC->TextOut(50, 50, sstate);
}
Update: Also look here for a similar, more detailed example http://www.codeproject.com/Articles/14706/Notifying-the-Document.
When it takes two minutes to just load something, then there are two reasons for that:
You are doing something stupid while loading, like e.g. running expensive algorithms on the data like indexing or graphical rendering. If you store the data in containers, the overhead of allocations could also become significant. If that is the case, only perform them on demand or perform these operations asynchronously in the background. You can notify the main thread (the one running the UI) when done in order to display the rendered graphics, for example.
The data is incredibly large. In that case, you will have to rethink how to access this data anyway, because any operation might be expensive. Your best bet will be to use an asynchronous model, like sending a request to the model to perform some operation. The model then sends a response to the UI to display the data. In that case, you need to think about how to make this transparent to the user though. One approach is to darken the display area after a change request and only brighten it up after the response or a progress bar.
I have a GUI and a worker thread, and I want to send data from the worker to the GUI. I'm using QueueEvent and wxThreadEvents to preserve model-view separation. I'm getting a baadf00d error somehow.
const int EvtID = 42;
MyFrame::MyFrame()
{
...
// this seems to work correctly,
// but I'm including it in case it is part of the problem
Bind(wxEVT_THREAD, (wxObjectEventFunction)&MyFrame::OutputData, this, EvtID);
...
}
MyFrame::OutputData(wxThreadEvent* event)
{
// should get data from MyThread,
// but outputs 0xBA, 0xAD, 0xF0, 0x0D in successive calls
output << event->GetInt();
}
MyThread::CreateOutputWithLocal()
{
wxThreadEvent event(wxEVT_THREAD, EvtID);
event.SetInt(getData());
//pFrame is a wxEvtHandler*
pFrame->QueueEvent(event.Clone());
}
MyThread::CreateOutputWithPointer()
{
wxThreadEvent* event = new wxThreadEvent(wxEVT_THREAD, EvtID);
event->SetInt(getData());
//pFrame is a wxEvtHandler*
pFrame->QueueEvent(event); // QueueEvent() takes control of the pointer and deletes it
}
Using wxThreadEvent's SetPayload() and GetPayload() or its SetExtraLong() and GetExtraLong() doesn't seem to make any difference. What do I need to get this to work?
Set/GetPayload should do the trick. May be you are doing it wrongly. Your code will be of more help. But here is a stripped example showing the usage of the Two methods.
Connect(wxID_ANY, wxEVT_COMMAND_DATA_SENT, wxThreadEventHandler(GMainFrame::OnAddText), NULL, this);//connect event to a method
void* MyThread::Entry(){
wxThreadEvent e(wxEVT_COMMAND_DATA_SENT);//declared and implemented somewhere
wxString text("I am sent!");
e.SetPayload(wxString::Format("%s", text.c_str()));
theParent->GetEventHandler()->AddPendingEvent(e);
return NULL;
}
void GMainFrame::OnAddText(wxThreadEvent& event) {
wxString t = event.GetPayload<wxString>();
wxMessageBox(t);
}
A stripped version from a sample I wrote long ago when playing around wxThreadEvent
In your case I would just store the pay load in a thread safe queue that would belong to the frame.
Before you queue the event, queue the data in the thread safe queue. In the OutputData function, flush the queue and read the data that is in it.
I'm using this strategy to pass boost::function < void () > to the UI, so it's very scallable, because I can trigger almost anything from the engine thread.
I'm capable to fill the database table in wxListCtrl,
my problem is to handle high range of data, I want to do this with the help of thread concept , perhaps it will save to hang the frame because of high amount of data.
I'm new in thread concept so your single lines will be a book for me.
Update:
My question was- how to display large data in wxListCtrl with using concept of wxThread
so for this I used thread concept I add two more files thread.c and thread.cpp
my entry thread code is shown below
void *MyThread :: Entry()
{
int i=1,j,k=0;
while(i!=400)
{
long index=this->temp->data_list_control->InsertItem(i,wxT("amit"));
for(j=1; j<3; j++) {
this->temp->data_list_control->SetItem(index,j,wxT("pathak"));
}
k++;
if(k==30) {
this->Sleep(1000);
k=0;
}
i++;
}
}
It is sometimes working fine but when I try to increase the value of i, it shows an error like
-*showingdatainwxlistctrl: ../../src/XlibInt.c:595: _XPrivSyncFunction: Assertion `dpy->synchandler == _XPrivSyncFunction' failed.*
or sometime it gives error like
***[Xcb] xcb_io.c:378: _XAllocID: Assertion `ret != inval_id' failed***
Why it is happening to me?
You can define your own thread object in wxWidgets in the following way:
class MyThread : public wxThread
{
private:
wxListCtrl* m_pListCtrl;
public:
MyThread(wxListCtrl* pListCtrl, wxThreadKind kind = wxTHREAD_DETACHED) :
wxThread(kind), m_pListCtrl(pListCtrl) {
}
virtual ~MyThread() {
}
virtual void* Entry() {
// here you have to place your code that will be running in separate thread
// m_pListCtrl-> ...
}
};
And this is the way how you can start your thread (assume you have your pListCtrl pointer here):
MyThread * pMyThread = new MyThread (pListCtrl);
wxThreadError ThreadError = pMyThread->Create();
if (wxTHREAD_NO_ERROR!=ThreadError) {
wxLogError(L"Can not create thread, wxThreadError '%d'", (int)ThreadError);
delete pMyThread;
return false;
}
ThreadError = pMyThread->Run();
if (wxTHREAD_NO_ERROR!=ThreadError) {
wxLogError(L"Can not run thread, wxThreadError '%d'", (int)ThreadError);
delete pMyThread;
return false;
}
// here, everything is ok.
Anyway, this is not the best solution for your problem. As far as I've understood, you need to display large amount of data in your wxListCtrl. To do this, you can use virtual ctrl (created with flag wxLC_VIRTUAL) and provide data source:
class MyListCtrl : public wxListCtrl
{
public:
MyListCtrl( ...) { ... }
virtual ~MyListCtrl();
protected:
virtual int OnGetItemImage(long item) const {
// You need this only if you want to provide specific image for your item.
// If you do not need it, just do not overload this method.
}
virtual wxString OnGetItemText(long item, long column) const {
// This is where you have to provide data for [item, column].
// Suppose, you have matrix A[n,m] which represents actually the data
// you want to display. The elements of this matrix can be of any type
// (strings, doubles, integers etc).
// You should return here wxString object that contains
// representation of the matrix's element A[item, column].
return ToWxString(A[item, column]);
// where ToWxString is your method that converts data to string
// So, you do not need to load all the data from A to wxListCtrl.
// Instead of it, wxListCtrl will determine which rows of the matrix should be
// displayed based on sizes and scroll position of wxListCtrl, and will
// call this method to obtain corresponding strings.
}
};
To create, you may use:
m_pListCtrl = new MyListCtrl( ..., ..., wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_VIRTUAL | wxSUNKEN_BORDER | wxLC_VRULES | wxLC_HRULES);
Best regards!
When you are performing high range of data you are bound to use WXThread in your program
Firstly was trying to fill wxListCtrl from wxEntry point, it was wrong u can not hit any main thread control from entry point, it does not give error, but it is a wrong concept
Here u need to pass the data to handler, handler will use it to fill wxListCtrl
code look like this->
void *MyThread :: Entry()
{
int a;
Handler handler_obj;
char *database_name=DATABASE_NAME;
connection =handler_obj.handler(101,database_name);
if(connection==NULL)
{
wxMessageBox(wxT("CAN NOT CONNECT TO DATABASE"), wxT("Message"), wxOK | wxICON_INFORMATION, NULL, -1, -1);
}
else
{
List_Ctrl_Data list_ctrl_data_object;
table_data=list_ctrl_data_object.fetch_table(connection);
MYSQL_ROW row;
while((row=mysql_fetch_row(table_data))!=NULL)
{
wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, 100000 );
void *row_data;
row_data=(void *)row;
event.SetClientData(row_data);
temp->GetEventHandler()->AddPendingEvent( event );
this->Sleep(1000);
}
}
}
to handle the row data we will use
void Id_Search_Report::onNumberUpdate(wxCommandEvent& evt)
{
int j;
void* hold_row;
hold_row=(void *)evt.GetClientData();
MYSQL_ROW row;
row=(MYSQL_ROW)hold_row;
const char* chars1 = row[0];
wxString mystring1(chars1, wxConvUTF8);
long index=data_list_control->InsertItem(this->counter,mystring1);
this->counter++;
for(j=1;j<12;j++)
{
const char* chars2=row[j];
wxString mystring2(chars2,wxConvUTF8);
data_list_control->SetItem(index,j,mystring2);
}
}
thread is returning a row , this method will handle the row and fill ListCtrl , it is a proper way to fill wxListCtrl.
I'm having problem (basically, I'm confused.) while trying to create a worker thread for my wxWidgets GUI application that WILL MODIFY one of the GUI property itself. (In this case, wxTextCtrl::AppendText).
So far, I have 2 source files and 2 header files for the wx program itself (excluding my own libs, MySQL lib, etc), say MainDlg.cpp which contains a derived class of wxFrame called 'MainDlg' and MainForm.cpp which contains a derived class of wxApp called 'MainForm'.
MainForm.cpp
#include "MainHeader.h" // contains multiple header files
IMPLEMENT_APP(MainForm)
bool MainForm::OnInit()
{
MainDlg *Server = new MainDlg(wxT("App Server 1.0"), wxDEFAULT_FRAME_STYLE - wxRESIZE_BORDER - wxMAXIMIZE_BOX);
Editor->Show();
return true;
}
MainDlg.cpp:
#include "MainHeader.h"
BEGIN_EVENT_TABLE(MainDlg, wxFrame)
EVT_BUTTON(6, MainDlg::StartServer)
EVT_BUTTON(7, MainDlg::StopServer)
END_EVENT_TABLE()
CNETServerConnection *cnServCon;
std::string ServerIP, DBHost, DBUser, DBName, DBPass;
int UserCapacity, DBPort, ServerPort;
MYSQL *sqlhnd;
MainDlg::MainDlg(const wxString &title, long style) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(301, 230), style)
{
cnServCon = new CNETServerConnection(100);
this->InitializeComponent();
}
void MainDlg::InitializeComponent()
{
this->SetTitle(wxT("App Server 1.0"));
this->SetSize(396, 260);
this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
this->Centre();
statBox = new wxTextCtrl(this, 4, wxT("Welcome to AppServer 1.0\n\n"), wxPoint(10, 10), wxSize(371, 141), wxTE_MULTILINE | wxTE_READONLY);
//.................................
}
void MainDlg::StartServer(wxCommandEvent &event)
{
this->startBtn->Enable(false);
this->AppendStatus(wxT("\nLoading server configuration... "));
//.................................
this->AppendStatus(wxT("OK\n\nServer ready!\n\n"));
// When the server is ready, I need to run a thread
// that will update the statBox (through AppendStatus func or wxTextCtrl::AppendText directly)
// regularly without interrupting the GUI itself.
// Because the thread will contain a while-loop
// to make the program keep receiving message from clients.
this->startBtn->Hide();
this->stopBtn->Show();
this->cmdBtn->Enable();
this->cmdBox->Enable();
}
void MainDlg::StopServer(wxCommandEvent &event)
{
//...................................
}
void MainDlg::AppendStatus(const wxString &message)
{
statBox->AppendText(message);
}
// Well, here is the function I'd like to run in a new thread
void MainDlg::ListenForMessages()
{
int MsgSender = 0;
while(1)
{
if(!cnServCon->GetNewMessage())
continue;
if(MsgSender = cnServCon->GetJoiningUser())
this->AppendStatus(wxT("Someone connected to the server."));
}
}
I also found an usage example of wxThread from Simple example of threading in C++:
class MessageThread : public wxThread
{
private:
MessageThread(const MessageThread ©);
public:
MessageThread() : wxThread(wxTHREAD_JOINABLE)
{
}
void *Entry(void)
{
// My works goes here
return;
}
};
wxThread *CreateThread()
{
wxThread *_hThread = new MessageThread();
_hThread->Create();
_hThread->Run();
return _hThread;
}
But I don't know how to associate it with my program and make it able to modify my GUI property (statBox).
Any kind of help would be appreciated! :)
Thanks.
The easiest is to create an event type id, and use a wxCommandEvent using the type id, set its string member ("evt.SetText"), and send the event to one of your windows (using AddPendingEvent). In the handler of that event, you can then call AppendText on your control using the text you sent (evt.GetText), because you are in the GUI thread by then.
// in header
DECLARE_EVENT_TYPE(wxEVT_MY_EVENT, -1)
// in cpp file
DEFINE_EVENT_TYPE(wxEVT_MY_EVENT)
// the event macro used in the event table. id is the window id you set when creating
// the `wxCommandEvent`. Either use -1 or the id of some control, for example.
EVT_COMMAND(window-id, event-id, handler-function)
Here is an overview how it works: Custom Events.
I've created a webservice and when I want to use its methods I instantiate it in the a procedure, call the method, and I finally I dispose it, however I think also it could be okay to instantiate the webservice in the "private void Main_Load(object sender, EventArgs e)" event.
The thing is that if I do it the first way I have to instantiate the webservice every time I need one of its methods but in the other way I have to keep a webservice connected all the time when I use it in a form for example.
I would like to know which of these practices are better or if there's a much better way to do it
Strategy 1
private void btnRead_Click(object sender, EventArgs e)
{
try
{
//Show clock
this.picResult.Image = new Bitmap(pathWait);
Application.DoEvents();
//Connect to webservice
svc = new ForPocketPC.ServiceForPocketPC();
svc.Credentials = new System.Net.NetworkCredential(Settings.UserName, Settings.Password);
svc.AllowAutoRedirect = false;
svc.UserAgent = Settings.UserAgent;
svc.PreAuthenticate = true;
svc.Url = Settings.Url;
svc.Timeout = System.Threading.Timeout.Infinite;
svc.CallMethod();
...
}
catch (Exception ex)
{
ShowError(ex);
}
finally
{
if (svc != null)
svc.Dispose();
}
}
Strategy 2
private myWebservice svc;
private void Main_Load(object sender, EventArgs e)
{
//Connect to webservice
svc = new ForPocketPC.ServiceForPocketPC();
svc.Credentials = new System.Net.NetworkCredential(Settings.UserName, Settings.Password);
svc.AllowAutoRedirect = false;
svc.UserAgent = Settings.UserAgent;
svc.PreAuthenticate = true;
svc.Url = Settings.Url;
svc.Timeout = System.Threading.Timeout.Infinite;
}
private void btnRead_Click(object sender, EventArgs e)
{
try
{
//Show clock
this.picResult.Image = new Bitmap(pathWait);
Application.DoEvents();
svc.CallMethod();
...
}
catch (Exception ex)
{
ShowError(ex);
}
}
private void Main_Closing(object sender, CancelEventArgs e)
{
svc.Dispose();
}
It depends on how often you are going to be calling the web service. If you're going to be calling it almost constantly, it would probably be better to use method #2. However, if it's not going to be getting called quite so often, you are better off using method #1, and only instantiating it when you need it.
Right now I made a solution for a mobile device and it turns to be used on irregular times, it could be used in 10 minutes, 1 hour, 4 hours its very variable, it seems that the better aproach is the first strategy.
Last year we went on a project where we used webservices, the fact is that we instantiated our webservices at the Sub New() procedure and it run it very well, however, sometimes some users claimed at us that they woke up from their chairs and when they returned and tried to continue on the application they received a timeout error message and they had to re-login again.
We thougth that maybe that was Ok because maybe the users went out for a very long time out of their seats, but once in a presentation of the application with the CEOs it happened exactly the same scenario and personally I didn't like that behaviour and that's why the question.
Thanks for the answer.