11//  Copyright (c) ZeroC, Inc.
22
3- #ifdef  _MSC_VER
4- //  For getenv
5- #    define  _CRT_SECURE_NO_WARNINGS 
6- #endif 
7- 
83#include  " Clock.h" 
4+ 
95#include  < Ice/Ice.h> 
106#include  < IceStorm/IceStorm.h> 
7+ 
118#include  < chrono> 
129#include  < ctime> 
10+ #include  < future> 
1311#include  < iostream> 
14- #include  < thread> 
1512
1613using  namespace  std ; 
1714using  namespace  Demo ; 
1815
19- int  run (const  shared_ptr<Ice::Communicator>& communicator, int  argc, char * argv[]);
16+ void 
17+ usage (const  char * name)
18+ {
19+     cerr << " Usage: " "  [--datagram|--twoway|--oneway] [topic]" 
20+ }
2021
2122int 
2223main (int  argc, char * argv[])
@@ -25,51 +26,24 @@ main(int argc, char* argv[])
2526    Ice::registerIceUDP ();
2627#endif 
2728
28-     int  status = 0 ;
29- 
30-     try 
31-     {
32-         // 
33-         //  CtrlCHandler must be created before the communicator or any other threads are started
34-         // 
35-         Ice::CtrlCHandler ctrlCHandler;
29+     //  CtrlCHandler is a helper class that handles Ctrl+C and similar signals. It must be constructed at the beginning
30+     //  of the program, before creating an Ice communicator or starting any thread.
31+     Ice::CtrlCHandler ctrlCHandler;
3632
37-         // 
38-         //  CommunicatorHolder's ctor initializes an Ice communicator,
39-         //  and its dtor destroys this communicator.
40-         // 
41-         const  Ice::CommunicatorHolder ich (argc, argv, " config.pub" 
42-         const  auto & communicator = ich.communicator ();
33+     //  Create an Ice communicator to initialize the Ice runtime.
34+     const  Ice::CommunicatorHolder communicatorHolder{argc, argv, " config.pub" 
35+     const  Ice::CommunicatorPtr& communicator = communicatorHolder.communicator ();
4336
44-         ctrlCHandler. setCallback ([communicator]( int ) { communicator-> destroy (); }); 
37+     //  Parse command-line options. 
4538
46-         status = run (communicator, argc, argv);
47-     }
48-     catch  (const  std::exception& ex)
49-     {
50-         cerr << ex.what () << endl;
51-         status = 1 ;
52-     }
53- 
54-     return  status;
55- }
56- 
57- void 
58- usage (const  string& n)
59- {
60-     cerr << " Usage: " "  [--datagram|--twoway|--oneway] [topic]" 
61- }
62- 
63- int 
64- run (const  shared_ptr<Ice::Communicator>& communicator, int  argc, char * argv[])
65- {
6639    enum  class  Option  : uint8_t 
6740    {
6841        None,
6942        Datagram,
7043        Twoway,
7144        Oneway
7245    };
46+ 
7347    Option option = Option::None;
7448    string topicName = " time" 
7549    int  i;
@@ -114,16 +88,15 @@ run(const shared_ptr<Ice::Communicator>& communicator, int argc, char* argv[])
11488        return  1 ;
11589    }
11690
117-     auto  manager = Ice::checkedCast<IceStorm::TopicManagerPrx>(communicator->propertyToProxy (" TopicManager.Proxy" 
91+     //  Create the topic manager proxy.
92+     auto  manager = communicator->propertyToProxy <IceStorm::TopicManagerPrx>(" TopicManager.Proxy" 
11893    if  (!manager)
11994    {
12095        cerr << argv[0 ] << " : invalid proxy" 
12196        return  1 ;
12297    }
12398
124-     // 
125-     //  Retrieve the topic.
126-     // 
99+     //  Retrieve the topic from IceStorm.
127100    optional<IceStorm::TopicPrx> topic;
128101    try 
129102    {
@@ -142,11 +115,11 @@ run(const shared_ptr<Ice::Communicator>& communicator, int argc, char* argv[])
142115        }
143116    }
144117
145-     // 
146-     //  Get the topic's publisher object, and create a Clock proxy with 
147-     //  the mode specified as an argument of this application. 
148-     // 
149-      auto  publisher = topic-> getPublisher (); 
118+     //  Get the topic's publisher object, and create a Clock proxy with the mode specified as an argument of this 
119+     //  application. 
120+     optional<Ice::ObjectPrx> publisher = topic-> getPublisher (); 
121+     assert (publisher);  //  getPublisher never returns nullopt 
122+ 
150123    if  (option == Option::Datagram)
151124    {
152125        publisher = publisher->ice_datagram ();
@@ -160,27 +133,56 @@ run(const shared_ptr<Ice::Communicator>& communicator, int argc, char* argv[])
160133        publisher = publisher->ice_oneway ();
161134    }
162135
136+     //  Downcast the proxy to the Clock type using uncheckedCast.
163137    auto  clock = Ice::uncheckedCast<ClockPrx>(publisher);
164138
165139    cout << " publishing tick events. Press ^C to terminate the application." 
166-     while  (true )
167-     {
168-         try 
140+ 
141+     promise<void > cancelPromise;
142+ 
143+     //  Send a tick every second until cancelled in a background task.
144+     auto  task = std::async (
145+         std::launch::async,
146+         [cancelFuture = cancelPromise.get_future (), clock = std::move (clock)]()
169147        {
170-             auto  now = chrono::system_clock::to_time_t (chrono::system_clock::now ());
171-             char  timeString[100 ];
172-             if  (strftime (timeString, sizeof (timeString), " %x %X" localtime (&now)) == 0 )
148+             while  (true )
173149            {
174-                 timeString[0 ] = ' \0 ' 
150+                 auto  now = chrono::system_clock::to_time_t (chrono::system_clock::now ());
151+                 char  timeString[100 ];
152+                 if  (strftime (timeString, sizeof (timeString), " %x %X" localtime (&now)) == 0 )
153+                 {
154+                     timeString[0 ] = ' \0 ' 
155+                 }
156+ 
157+                 try 
158+                 {
159+                     clock->tick (timeString);
160+                 }
161+                 catch  (const  Ice::CommunicatorDestroyedException&)
162+                 {
163+                     break ; //  done
164+                 }
165+ 
166+                 //  Sleep for one second or until canceled.
167+                 if  (cancelFuture.wait_for (chrono::seconds (1 )) == future_status::ready)
168+                 {
169+                     break ; //  done
170+                 }
175171            }
176-             clock->tick (timeString);
177-             this_thread::sleep_for (chrono::seconds (1 ));
178-         }
179-         catch  (const  Ice::CommunicatorDestroyedException&)
180-         {
181-             break ;
182-         }
183-     }
172+         });
173+ 
174+     //  Wait until the user presses Ctrl+C.
175+     int  signal = ctrlCHandler.wait ();
176+     cout << " Caught signal " " , exiting..." 
177+ 
178+     //  Cancel the sleep in the background task.
179+     cancelPromise.set_value ();
180+ 
181+     //  Destroy the communicator in case a call to tick is taking a long time.
182+     communicator->destroy ();
183+ 
184+     //  Wait for the background task to complete.
185+     task.wait ();
184186
185187    return  0 ;
186188}
0 commit comments