Hello,

I am writing a multi-threaded C# console program that
is executed by a windows Service which acts as a Service Control
Manager
for the console app and thereby executes the application
 as a Service.

For the Service to run the apps as a Service, they have to be written
a certain way.
The Service works by starting up a process for the application, before
executing the app code.

On entering the main method of the app, it tests for a Mutex and as
long as there is already a mutex when the service was started, the
conditions will make the app run endlessly unless the controlling
service is stopped.


The main issue is that I have been having some unexpected results in
the execution of the app. There are 2 threads running concurrently but
sometimes it seems like one thread is smothered or deprived of
resources for execution.

Here is the source code.




namespace BulkSmsClient
{
    class Program
    {
        static Mutex mSingleton;
        private static readonly ILog log =
LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        public static Thread T1;
        public static Thread T2;
        private static object gate = new object();
        private static object gate2 = new object();
        //BELOW THE VARIABLE FOR MANAGING THIS AS SERVICE USING
PROCESS MANAGER (VAS SYSTEM MANAGER)// REMOVE IF NOT NEEDED
        private static bool m_isApplicationTerminating;
        //END

        static void Main(string[] args)
        {
            try
            {
                //CAUTION: UNCOMMENT THE MUTEX TEST CODE BLOCK BELOW
IF YOU ARE NOT USING THE PROCESS MANAGER SERVICE.
                //Check if there is already an instance of the
application running
                //Kill second instance if true
                //REQUIRES reference to the System.Threading namespace
                //bool created;
                //mSingleton = new Mutex(true, "BulkSmsClient", out
created);
                //if (!created)
                //{
                //    Console.WriteLine("Already running, exiting");
                //    return;
                //}


                //Configure log4net passing in the log4net.xml config
file at the Application root folder.
                XmlConfigurator.Configure(new
System.IO.FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location.Remove(System.Reflection.Assembly.GetExecutingAssembly().Location.LastIndexOf("\
\BulkSmsClient.exe")) + "\\log4net.xml"));


                //// log4net configuration in the app.config file here
for configuring this to log to the PROCESS MANAGER's Global log file
                //string appId = String.Format(@"{0}\{1}.exe",
Environment.CurrentDirectory,
                //
Assembly.GetExecutingAssembly().GetName().Name);

                //XmlConfigurator.Configure();
                //log4net.GlobalContext.Properties["identity"] =
appId;


                log.Info("Entering Application...");

                log.Debug("Initialising ServicePointManager to use the
Certificate Policy...");
                //DEPRECATED: Get the ServicePointManager to use the
Certificate Policy. This allows you to use HTTPS with self-signed
certificates
                //System.Net.ServicePointManager.CertificatePolicy =
new TrustAllCertificatePolicy();

                // CURRENT: allows for validation of SSL conversations
                //Requires the following imports:
                //using System.Net.Security;
                //using System.Security.Cryptography.X509Certificates;
                //and the Callback method below:
ValidateRemoteCertificate
                //TODO: Separate into a Class
 
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
new RemoteCertificateValidationCallback(
                    ValidateRemoteCertificate
                );

                //Retrieving the AppSettings Section of the
Configuration file
                NameValueCollection nvcAllAppSettings =
ConfigurationManager.AppSettings;

                //BELOW THE VARIABLES FOR MANAGING THIS AS SERVICE
USING PROCESS MANAGER (VAS SYSTEM MANAGER)// REMOVE IF NOT NEEDED
                Mutex mutex = null;
                bool isFirstInstance = true;
                m_isApplicationTerminating = false;
                //END

                log.Debug("Enter Main method");

                log.Debug(string.Format("Main Thread Id {0}",
Thread.CurrentThread.ManagedThreadId.ToString()));

                T1 = new Thread(new
ParameterizedThreadStart(sendMessage));
                T2 = new Thread(new
ParameterizedThreadStart(updateDeliveryReportsDB));


                T1.Start(nvcAllAppSettings);
                T2.Start(nvcAllAppSettings);

                // Continue whilst there are active threads
                while (!m_isApplicationTerminating)
                {

                    if (!m_isApplicationTerminating)
                    {
                        //mutex = new Mutex(false,
Environment.CurrentDirectory, out isFirstInstance);
                        string mutexname =
String.Format(@"{0}\{1}.exe", Environment.CurrentDirectory,
Assembly.GetExecutingAssembly().GetName().Name);
                        mutex = new Mutex(false,
mutexname.Replace(@"\", String.Empty), out isFirstInstance);
                    }
                    if (isFirstInstance)
                    {
                        m_isApplicationTerminating = true;
                    }
                    else
                    {
                        if (mutex != null)
                        {
                            mutex.Close();
                        }
                        //Thread.Sleep(1000);
                    }
                }

                log.Debug("Exit Main method");


            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
        }

        private static void sendMessage(object m_nvcAllAppSettings)
        {
            while (!m_isApplicationTerminating)
            {
                log.Debug(string.Format("Inside SendMessage Thread
with Thread Id {0}",
Thread.CurrentThread.ManagedThreadId.ToString()));

                NameValueCollection nvcAllAppSettings =
(NameValueCollection)m_nvcAllAppSettings;

                //Instantiate Web Service
                try
                {

                    int i = 0;
                    string strVendor = String.Empty;
                    //DateTime datStartTime;
                    //DateTime datEndTime;
                    Service messageController;
                    ClientMessageResult result;
                    ClientInfo client = null;
                    ClientMessage message;
                    service1 retrieveTransLog;
                    TransactionLog[] transactionlog;
                    string[] strGuidResult;
                    string messageId = string.Empty;
                    //TransactionScope transaction = null;


                    //Initialising the A3BulkSmsDeliveryReports
WebService
                    retrieveTransLog = new service1();

                    log.Debug("Connecting to host: " +
BulkSmsClient.Properties.Settings.Default.BulkSmsClient_org_dyndns_a3ando_Service);
                    messageController = new Service();
                    log.Debug("Connected successfully to host: " +
BulkSmsClient.Properties.Settings.Default.BulkSmsClient_org_dyndns_a3ando_Service);



                    log.Debug("Reading data from the messaging source
table - Sms2Vendor.");
                    //Read data from the messaging source table -
Sms2Vendor.
                    DataTable dtDueSms =
Sms2Vendor.GetDueSms2Vendor();



                    result = null;
                    client = new ClientInfo();
                    message = new ClientMessage();

                    string strMessageBody = String.Empty;

                    // My-Id will be replaced by a Client Id supplied
by A3&O
                    client.ClientId = nvcAllAppSettings["ClientId"];

                    // My-Key will be replaced by a Client Key
supplied by A3&O
                    client.ClientKey =
nvcAllAppSettings["Authorization"];

                    //client.ClientName = @"ADMIN";
                    client.ClientName =
nvcAllAppSettings["ClientName"];

                    if (dtDueSms.Rows.Count > 0)
                    {
                        for (int m = 0; m < dtDueSms.Rows.Count; m++)
                        {
                            //Construct message

                            strMessageBody = dtDueSms.Rows[m]
["Message"].ToString();

                            message.Header = (!
string.IsNullOrEmpty(dtDueSms.Rows[m]["SenderId"].ToString())) ?
dtDueSms.Rows[m]["SenderId"].ToString() : nvcAllAppSettings["Header"];
                            message.Body = strMessageBody;
                            message.DestinationAddress =
dtDueSms.Rows[m]["PhoneNo"].ToString();

                            //Set other parameters
                            strVendor = (!
string.IsNullOrEmpty(dtDueSms.Rows[m]["Vendor"].ToString())) ?
dtDueSms.Rows[m]["Vendor"].ToString() : nvcAllAppSettings["Vendor"];

                            //Get the time before the Server submit is
done
                            //string strStartTime =
retrieveTransLog.GetServerDateTime();

                            //Submit the message. Send it to the phone
and log the transaction.
                            log.Debug("Sending the sms");
                            result =
messageController.SubmitMessage(client, message);
                            log.Debug("Completed Sending the sms.
Status: " + result.Result.ToString());
                            //Thread.Sleep(5000);

                            //Extract guid
                            if (result.Result.ToString().ToUpper() ==
"OK")
                            {
                                strGuidResult =
result.Message.ToString().Split(':');
                                messageId = strGuidResult[2].Trim();
                            }
                            else
                            {
                                messageId = null;
                            }

                            //NEED TO TEST THAT Result returns OK here
or else return from method
                            if (result != null)
                            {
                                if (result.Result.ToString().ToUpper()
== "OK")
                                {

                                    //Mark this scope as transactional
and starting a transaction
                                    //transaction = new
TransactionScope();

                                    lock (gate)
                                    {
                                        //Update the tables to
indicate that message has been sent but not yet delivered
                                        i =
Sms2Vendor.UpdateSentButUndelivrdSms(dtDueSms.Rows[m]
["AutoID"].ToString(), dtDueSms.Rows[m]["PhoneNo"].ToString(),
dtDueSms.Rows[m]["Message"].ToString(), strVendor, null,
DateTime.Parse(dtDueSms.Rows[m]["DateSent"].ToString()), null, 5,
null, message.Header, messageId, dtDueSms.Rows[m]
["Msg_Type"].ToString());
                                    }

                                    //Commit the transaction
                                    //transaction.Complete();
                                    //Dispose the transaction object
                                    //transaction.Dispose();
                                }
                                else
                                {
                                    //Log the errorneous
                                    lock (gate)
                                    {
                                        //Update the tables to
indicate that message has been sent but not yet delivered

                                        i =
Sms2Vendor.UpdateSentButUndelivrdSms(dtDueSms.Rows[m]
["AutoID"].ToString(), dtDueSms.Rows[m]["PhoneNo"].ToString(),
dtDueSms.Rows[m]["Message"].ToString(), strVendor, null,
DateTime.Parse(dtDueSms.Rows[m]["DateSent"].ToString()), null, 5,
null, message.Header, messageId, dtDueSms.Rows[m]
["Msg_Type"].ToString());
                                    }

 
log.Debug(result.Result.ToString().ToUpper());
                                }
                            }



                            transactionlog =
retrieveTransLog.GetTransactionLog(client.ClientId, messageId);



                            if (result != null)
                            {
                                if (result.Result.ToString().ToUpper()
== "OK")
                                {
                                    if (transactionlog.Length > 0)
                                    {
                                        //Update the messaging source
table - Sms2Vendor//Insert into the Report table - VendorSmsReport
                                        if
(transactionlog[0].Status.ToLower().Trim() == "delivrd")
                                        {
                                            log.Debug("Sms was
DELIVERED. Updating the Sms2Vendor and VendorSmsReport tables");
                                            //To add more
transactional support for the two statements below

                                            //Mark this scope as
transactional and starting a transaction
                                            //transaction = new
TransactionScope();

                                            lock (gate)
                                            {

                                                i =
Sms2Vendor.UpdateDelivrdSms(dtDueSms.Rows[m]["AutoID"].ToString(),
message.DestinationAddress, message.Body, strVendor, null,
DateTime.Parse(dtDueSms.Rows[m]["DateSent"].ToString()),
transactionlog[0].Status, 1,
DateTime.Parse(transactionlog[0].DeliveryDateTime), message.Header,
messageId, dtDueSms.Rows[m]["Msg_Type"].ToString());
                                            }

                                            //Commit the transaction
                                            //transaction.Complete();

                                            //End this transaction
scope by disposing the transaction object
                                            //transaction.Dispose();

                                            log.Debug("Update
complete");
                                        }
                                        else
                                        {
                                            log.Debug("Sms NOT YET
DELIVERED. Updating the Sms2Vendor and VendorSmsReport tables");

                                            //Mark this scope as
transactional and starting a transaction
                                            //transaction = new
TransactionScope();

                                            lock (gate)
                                            {

                                                i =
Sms2Vendor.UpdateDelivrdSms(dtDueSms.Rows[m]["AutoID"].ToString(),
message.DestinationAddress, message.Body, strVendor, null,
DateTime.Parse(dtDueSms.Rows[m]["DateSent"].ToString()),
transactionlog[0].Status, 5, null, message.Header, messageId,
dtDueSms.Rows[m]["Msg_Type"].ToString());
                                            }

                                            //Commit the transaction
                                            //transaction.Complete();

                                            //End this transaction
scope by disposing the transaction object
                                            //transaction.Dispose();

                                            log.Debug("Update
complete");
                                        }
                                    }

                                    //Console.WriteLine("OK");
                                    log.Debug("OK");
                                }
                                else
                                {
 
log.Debug(result.Result.ToString().ToUpper());
                                }
                            }
                            // Sleep after each iteration
                            Thread.Sleep(1000);
                        }

                    }//Comment out the else block below to execute the
Application indefinitely or forever.
                    else
                    {
                        Thread.Sleep(1000);
                    }


                    //}
                }
                catch (Exception ex)
                {
                    log.Error(ex.Message);
                }

                log.Debug(string.Format("Exiting SendMessage Thread
with Thread Id {0}",
Thread.CurrentThread.ManagedThreadId.ToString()));
            }
        }

        private static void updateDeliveryReportsDB(object
m_nvcAllAppSettings)
        {
            while (!m_isApplicationTerminating)
            {
                log.Debug(string.Format("Inside
UpdateDeliveryReportsDB Thread with Thread Id {0}",
Thread.CurrentThread.ManagedThreadId.ToString()));

                NameValueCollection nvcAllAppSettings =
(NameValueCollection)m_nvcAllAppSettings;

                try
                {

                //int i = 0;
                string strVendor = String.Empty;
                //DateTime datStartTime;
                //DateTime datEndTime;
                //Service messageController;
                //ClientMessageResult result;
                ClientInfo client = new ClientInfo(); ;
                //ClientMessage message;
                service1 retrieveTransLog = new service1(); ;
                TransactionLog[] transactionlog;
                //TransactionScope transaction = null;

                //Loop through Database and update Delivery reports
                DataTable dtGetTop10UndeliveredSms =
Sms2Vendor.GetTop10UndeliveredSms(nvcAllAppSettings["Vendor"]);



                    if (dtGetTop10UndeliveredSms.Rows.Count > 0)
                    {
                        for (int j = 0; j <
dtGetTop10UndeliveredSms.Rows.Count; j++)
                        {

                            if (client == null)
                            {
                                client = new ClientInfo();
                            }


                            client.ClientId = (!
string.IsNullOrEmpty(client.ClientId)) ? client.ClientId :
nvcAllAppSettings["ClientId"];


                            if (retrieveTransLog == null)
                            {
                                retrieveTransLog = new service1();
                            }

                            transactionlog =
retrieveTransLog.GetTransactionLog(client.ClientId,
dtGetTop10UndeliveredSms.Rows[j]["MessageId"].ToString());

                            //Update the local Database tables
                            if ((transactionlog.Length > 0) &&
(transactionlog[0].Status.ToLower().Trim() == "delivrd"))
                            {
                                //We have a match
                                //Update the Sms2Vendor table

                                log.Debug("Sms was DELIVERED. Updating
the Sms2Vendor and VendorSmsReport tables");
                                //Mark this scope as transactional and
starting a transaction
                                //transaction = new
TransactionScope();

                                lock (gate2)
                                {

                                    int k =
Sms2Vendor.UpdateDelivrdSms(dtGetTop10UndeliveredSms.Rows[j]
["AutoID"].ToString(), dtGetTop10UndeliveredSms.Rows[j]
["PhoneNo"].ToString(), dtGetTop10UndeliveredSms.Rows[j]
["Message"].ToString(), dtGetTop10UndeliveredSms.Rows[j]
["Vendor"].ToString(), null,
DateTime.Parse(dtGetTop10UndeliveredSms.Rows[j]
["DateSent"].ToString()), transactionlog[0].Status, 1,
DateTime.Parse(transactionlog[0].DeliveryDateTime),
dtGetTop10UndeliveredSms.Rows[j]["SenderId"].ToString(),
dtGetTop10UndeliveredSms.Rows[j]["MessageId"].ToString(),
dtGetTop10UndeliveredSms.Rows[j]["Msg_Type"].ToString());
                                }

                                //Commit the transaction
                                //transaction.Complete();

                                //End this transaction scope by
disposing the transaction object
                                //transaction.Dispose();

                                log.Debug("Update complete");
                            }

                            //Sleep after each iteration
                            Thread.Sleep(1000);
                        }
                    }
                }
                catch(Exception ex)
                {
                    log.Error(ex.Message);
                }
                log.Debug(string.Format("Exiting
UpdateDeliveryReportsDB Thread with Thread Id {0}",
Thread.CurrentThread.ManagedThreadId.ToString()));
            }
        }

Reply via email to