examples/Base/SmpExample/src/SmpExample.cpp

00001 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
00002 // All rights reserved.
00003 // This component and the accompanying materials are made available
00004 // under the terms of "Eclipse Public License v1.0"
00005 // which accompanies this distribution, and is available
00006 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
00007 //
00008 // Initial Contributors:
00009 // Nokia Corporation - initial contribution.
00010 //
00011 // Contributors:
00012 //
00013 
00014 #include <d32dbms.h>  //Used for RDbDatabase class. 
00015 #include "SmpExample.h"
00016 _LIT(KDatabase1, "C:\\DBforSMP1.db");
00017 _LIT(KDatabase2, "C:\\DBforSMP2.db");
00018 
00022 CSmpExample::~CSmpExample()
00023     {
00024     iReadThread.Close(); //Reader thread closed. 
00025     iWriteThread1.Close(); //Writer thread closed. 
00026     iWriteThread2.Close(); //Writer thread closed.
00027     delete iConsole;
00028     }
00029 
00033 CSmpExample* CSmpExample::NewL()
00034     {
00035     CSmpExample* self = new(ELeave)CSmpExample();
00036     CleanupStack::PushL(self);
00037     self->ConstructL();
00038     CleanupStack::Pop(self);
00039     return self;
00040     }
00041 
00045 void CSmpExample::ConstructL()
00046     { 
00047     CreateDatabaseL(KDatabase1);
00048     CreateDatabaseL(KDatabase2);
00049     
00050     _LIT(KTextConsoleTitle, "SmpExample");
00051     iConsole = Console::NewL(KTextConsoleTitle, TSize(KConsFullScreen, KConsFullScreen));  
00052 
00053     //Creates a reader thread to read the databases.
00054     _LIT(KReader, "ReaderThread");
00055     User::LeaveIfError(iReadThread.Create(KReader, ReadThreadFuncL, KDefaultStackSize, KMinHeapSize, 256*KMinHeapSize, this, EOwnerProcess));   
00056 
00057     //Creates a writer thread to write to the DBforSMP1.db database. 
00058     _LIT(KWriter1, "WriterThread1");
00059     User::LeaveIfError(iWriteThread1.Create(KWriter1, WriteThread1FuncL, KDefaultStackSize, KMinHeapSize, 256*KMinHeapSize, this, EOwnerProcess));    
00060     
00061     //Creates a writer thread to write to the DBforSMP2.db database. 
00062     _LIT(KWriter2, "WriterThread2");
00063     User::LeaveIfError(iWriteThread2.Create(KWriter2, WriteThread2FuncL, KDefaultStackSize, KMinHeapSize, 256*KMinHeapSize, this, EOwnerProcess));           
00064 
00065 
00066     //Sets priority to the threads. 
00067     iWriteThread1.SetPriority(EPriorityMuchLess);
00068     iWriteThread2.SetPriority(EPriorityMore);
00069     iReadThread.SetPriority(EPriorityNormal);
00070     }
00071 
00075 void CSmpExample::StartThreads()
00076     {   
00077     TRequestStatus writerThread1Status; 
00078     TRequestStatus readerThreadStatus; 
00079     TRequestStatus writerThread2Status; 
00080     
00081     _LIT(KTextPressKey, "\nPress any key to start writing to and reading from the database\n");
00082     iConsole->Printf(KTextPressKey);
00083     iConsole->Getch();
00084   
00085     //Requests a notification for the ReaderThread to terminate. 
00086     iReadThread.Logon(readerThreadStatus);
00087     iReadThread.Resume();
00088     
00089     //Requests a notification for the WriterThread1 to terminate. 
00090     iWriteThread1.Logon(writerThread1Status);   
00091     iWriteThread1.Resume();
00092     
00093     //Requests a notification for the WriterThread2 to terminate. 
00094     iWriteThread2.Logon(writerThread2Status);   
00095     iWriteThread2.Resume();
00096     
00097     //Control returns to the main thread when the all the threads terminate. 
00098     User::WaitForRequest(writerThread1Status);
00099     User::WaitForRequest(readerThreadStatus);
00100     User::WaitForRequest(writerThread2Status);
00101     }
00102 
00106 void CSmpExample::PrintMessage()
00107     {
00108     _LIT(KTextWelcome, "Welcome to the SmpExample.\n");
00109     _LIT(KTextPurposel1, "There are three threads running in the example: WriterThread1 has the lowest priority,\n");
00110     _LIT(KTextPurposel2, "ReaderThread has normal priority and WriterThread2 has maximum priority.\n");  
00111     _LIT(KTextPurposel3, "The two WriterThreads open two different databases and write some integers to them.\n");
00112     _LIT(KTextPurposel4, "ReaderThread reads the two databases and prints the output to the console.\n");
00113     
00114     _LIT(KTextPurposel5, "In a unicore environment, WriterThread1 will be scheduled to run last and would not have\n");
00115     _LIT(KTextPurposel6, "written to the database when ReaderThread starts reading the databases.\n");
00116     _LIT(KTextPurposel7, "But in an SMP environment, both the WriterThreads write to their respective databases simultaneously.\n");
00117     
00118     iConsole->Printf(KTextWelcome);
00119     iConsole->Printf(KTextPurposel1);
00120     iConsole->Printf(KTextPurposel2);
00121     iConsole->Printf(KTextPurposel3);
00122     iConsole->Printf(KTextPurposel4);
00123     iConsole->Printf(KTextPurposel5);
00124     iConsole->Printf(KTextPurposel6);
00125     iConsole->Printf(KTextPurposel7);
00126     }
00127 
00131 void CSmpExample::ReadDatabaseL(const TDesC& aDbName, CConsoleBase& console)
00132     { 
00133     //Creates a file server session object before any file system manipulation. 
00134     RFs fsSession;
00135     CleanupClosePushL(fsSession);
00136     fsSession.Connect();
00137     
00138     //Creates Rdbs object
00139     RDbs dbs;
00140     CleanupClosePushL(dbs); 
00141     dbs.Connect();
00142     
00143     //Opens the named database using the RDbs object
00144     RDbNamedDatabase database;
00145     CleanupClosePushL(database);
00146     User::LeaveIfError(database.Open(dbs, aDbName)); 
00147     
00148     //Locks the database.
00149     database.Begin();
00150     //Prepare an SQL query to read one row of numbers from the database. 
00151     _LIT(KSQLStatement, "Select Number1, Number2, Number3  from Numbers order by Number1, Number2, Number3");
00152     
00153     //Creates a view on the database to read it.
00154     RDbView view; 
00155     CleanupClosePushL(view);
00156     
00157     User::LeaveIfError(view.Prepare(database, TDbQuery(KSQLStatement, EDbCompareNormal)));
00158     User::LeaveIfError(view.EvaluateAll());
00159     
00160     _LIT(KTextReading, "Reading the database\t %S.\n");
00161     console.Printf(KTextReading, &aDbName);
00162     
00163     //Boolean variable to check whether the database is empty.
00164     TBool isDbEmpty= EFalse;
00165     //Iterates through the database till the last row is read. 
00166     for (view.FirstL(); view.AtRow(); view.NextL())
00167         {       
00168         view.GetL();
00169         TInt number1 = view.ColInt(1);
00170         TInt number2 = view.ColInt(2);
00171         TInt number3 = view.ColInt(3);
00172         //Prepare a row formatter to print numbers in the console. 
00173         _LIT(KRowFormatter, "Reading  %d \t%d\t%d\n");  
00174         //Reads the integers from the view and display them in the console.
00175         console.Printf(KRowFormatter, number1, number2, number3);
00176         isDbEmpty= ETrue;
00177         }
00178     
00179     if(isDbEmpty== EFalse)
00180         {
00181         _LIT(KTextDbEmpty, "Database is empty.\n\n");
00182         console.Printf(KTextDbEmpty);
00183         }
00184     else
00185         {
00186         _LIT(KTextAllRead, "All the numbers in the database have been read.\n\n");
00187         console.Printf(KTextAllRead);
00188         }            
00189     
00190     CleanupStack::PopAndDestroy(&view); 
00191     CleanupStack::PopAndDestroy(&database);  
00192     CleanupStack::PopAndDestroy(&dbs);    
00193     CleanupStack::PopAndDestroy(&fsSession);
00194     }
00195 
00199 void CSmpExample::ReadBothDatabasesL()
00200     {
00201     _LIT(KTextConsoleTitle, "ReaderThread");
00202     CConsoleBase* console= Console::NewL(KTextConsoleTitle, TSize(KConsFullScreen, KConsFullScreen)); 
00203     CleanupStack::PushL(console);
00204 
00205     //Reads DBforSMP1.db and prints the output to the console. 
00206     ReadDatabaseL(KDatabase1, *console);
00207     //Reads DBforSMP2.db and prints the output to the console.
00208     ReadDatabaseL(KDatabase2, *console);
00209     
00210     _LIT(KExit, "Press any key to exit\n");
00211     console->Printf(KExit);
00212     console->Getch();
00213     CleanupStack::PopAndDestroy(console);    
00214     }
00215 
00220 TInt CSmpExample::ReadThreadFuncL(TAny* /*aPtr*/)
00221     {
00222     __UHEAP_MARK;
00223     //Creates cleanup stack.
00224     CTrapCleanup* cleanup = CTrapCleanup::New();
00225     if(!cleanup)
00226         {
00227         return KErrNoMemory;
00228         }
00229      
00230     TRAPD(error, ReadBothDatabasesL()); 
00231     if(error != KErrNone)
00232         {
00233         _LIT(KUserPanic, "DB Read Failed");  
00234         User::Panic(KUserPanic, error);
00235         }
00236     delete cleanup;
00237     __UHEAP_MARKEND;
00238     return KErrNone;
00239     }
00240 
00245 void CSmpExample::WriteDbFuncL(const TDesC& aDbName, TInt aNum)
00246     {
00247     //Creates a file server session object before any file system manipulation. 
00248     RFs fsSession;
00249     CleanupClosePushL(fsSession);
00250     fsSession.Connect();
00251 
00252 
00253     //Creates Rdbs object   
00254     RDbs dbs;
00255     CleanupClosePushL(dbs);
00256     dbs.Connect();
00257     
00258     //Opens the database using the RDbs object
00259     RDbNamedDatabase database;
00260     CleanupClosePushL(database);
00261     User::LeaveIfError(database.Open(dbs, aDbName)); 
00262     
00263     //Locks the database.
00264     database.Begin();
00265     
00266     //Creates a view on the database. 
00267     RDbView view;
00268     CleanupClosePushL(view);
00269     _LIT(KSQLStatement, "Select Number1, Number2, Number3 from Numbers order by Number1, Number2, Number3");
00270     User::LeaveIfError(view.Prepare(database, TDbQuery(KSQLStatement, EDbCompareNormal)));
00271     User::LeaveIfError(view.EvaluateAll());
00272 
00273     for(int i=0; i<5; i++)
00274         {
00275         //Inserts a new row at the end of the database. 
00276         view.InsertL();
00277         //Fills three columns with numbers.
00278         view.SetColL(1, aNum++);
00279         view.SetColL(2, aNum++);
00280         view.SetColL(3, aNum++);
00281         view.PutL();
00282         }
00283 
00284     CleanupStack::PopAndDestroy(&view);       
00285     //Commits the database and unlocks it. 
00286     database.Commit();
00287     CleanupStack::PopAndDestroy(&database);  
00288     CleanupStack::PopAndDestroy(&dbs);   
00289     CleanupStack::PopAndDestroy(&fsSession);
00290     }
00291 
00292 
00297 TInt CSmpExample::WriteThread2FuncL(TAny* /*aPtr*/)
00298     {
00299     __UHEAP_MARK;
00300     //Creates cleanup stack.
00301     CTrapCleanup* cleanup = CTrapCleanup::New();
00302     if(!cleanup)
00303         {
00304         return KErrNoMemory;
00305         }
00306     
00307     //First number to be written to the database. 
00308     const int KFirstNumforDb2 = 500; 
00309     TRAPD(err, WriteDbFuncL(KDatabase2, KFirstNumforDb2));
00310     if(err != KErrNone)
00311         {
00312         _LIT(KUserPanic, "DB Write Failed");  
00313         User::Panic(KUserPanic, err);
00314         }
00315     delete cleanup;
00316     __UHEAP_MARKEND;
00317     return KErrNone;
00318     }
00319 
00324 TInt CSmpExample::WriteThread1FuncL(TAny* /*aPtr*/)
00325     {
00326     __UHEAP_MARK;
00327     //Creates cleanup stack.
00328     CTrapCleanup* cleanup = CTrapCleanup::New();
00329     if(!cleanup)
00330         {
00331         return KErrNoMemory;
00332         }
00333 
00334     //First number to be written to the database. 
00335     const int KFirstNumforDb1 = 0; 
00336     TRAPD(err, WriteDbFuncL(KDatabase1, KFirstNumforDb1));
00337     if(err != KErrNone)
00338         {
00339         _LIT(KUserPanic, "DB Write Failed");  
00340         User::Panic(KUserPanic, err);
00341         }
00342     delete cleanup;
00343     __UHEAP_MARKEND;
00344     return KErrNone;
00345     }
00346 
00351 void CSmpExample::CreateDatabaseL(const TDesC& aDbName)
00352     {
00353     //Creates a file server session object before any file system manipulation. 
00354     RFs fsSession;
00355     CleanupClosePushL(fsSession);
00356     fsSession.Connect();
00357 
00358     //Creates Rdbs object
00359     RDbs dbs;
00360     CleanupClosePushL(dbs); 
00361     dbs.Connect();
00362     
00363     //Creates a new database with the name specified in the parameter aDbName, 
00364     //if database with same name is present, it will be replaced.    
00365     RDbNamedDatabase database;
00366     CleanupClosePushL(database);  
00367     User::LeaveIfError(database.Replace(fsSession, aDbName)); 
00368     database.Close(); 
00369     
00370     //Opens the database using the RDbs object
00371     User::LeaveIfError(database.Open(dbs, aDbName));       
00372     //Creates a table definition.
00373     CDbColSet* columns=CDbColSet::NewLC();
00374 
00375     //Adds three columns each containing Int32 values. 
00376     _LIT(KCol1, "Number1");
00377     _LIT(KCol2, "Number2");
00378     _LIT(KCol3, "Number3");   
00379     columns->AddL(TDbCol(KCol1, EDbColInt32));
00380     columns->AddL(TDbCol(KCol2, EDbColInt32));
00381     columns->AddL(TDbCol(KCol3, EDbColInt32));
00382  
00383 
00384      //Creates the table, table name is "Numbers" and add the columns to it.
00385     _LIT(KTable, "Numbers");
00386     User::LeaveIfError(database.CreateTable(KTable, *columns));
00387     
00388     CDbKey* key=CDbKey::NewLC();
00389 
00390      //Add the key columns.
00391      TDbKeyCol number1(KCol1);
00392      key->AddL(number1);
00393      TDbKeyCol number2(KCol2);
00394      key->AddL(number2);
00395      TDbKeyCol number3(KCol3);
00396      key->AddL(number3);
00397     User::LeaveIfError(database.CreateIndex(KTable, KTable, *key));
00398     
00399     //Cleans up the column set.  
00400     CleanupStack::PopAndDestroy(key);
00401     CleanupStack::PopAndDestroy(columns);  
00402     CleanupStack::PopAndDestroy(&database);  
00403     CleanupStack::PopAndDestroy(&dbs);   
00404     CleanupStack::PopAndDestroy(&fsSession);
00405     }
00406 
00411 static void MainL()
00412     {
00413     CSmpExample* smpExample = CSmpExample::NewL();
00414     CleanupStack::PushL(smpExample);    
00415     smpExample->PrintMessage();
00416     smpExample->StartThreads();
00417     CleanupStack::PopAndDestroy(smpExample);
00418     }
00419 
00423 extern TInt E32Main()
00424     {
00425     //Creates cleanup stack.
00426     __UHEAP_MARK;
00427     CTrapCleanup* cleanup = CTrapCleanup::New();
00428     if(!cleanup)
00429         {
00430         return KErrNoMemory;
00431         }
00432     //Run application code inside a TRAP harness.
00433     TRAPD(mainError, MainL());
00434     if(mainError != KErrNone)
00435         {
00436         _LIT(KUserPanic, "Main Failed");  
00437         User::Panic(KUserPanic, mainError);
00438         }
00439     delete cleanup;
00440     __UHEAP_MARKEND;
00441     return KErrNone;
00442     }
00443 

Generated by  doxygen 1.6.2