Skip to content

Commit f42a74f

Browse files
Cleanup C++ IceStorm/clock (#263)
1 parent 9f0fb33 commit f42a74f

File tree

15 files changed

+206
-244
lines changed

15 files changed

+206
-244
lines changed

cpp/IceStorm/clock/Clock.ice

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44

55
module Demo
66
{
7+
/// The interface implemented by the subscriber. It accepts time updates.
78
interface Clock
89
{
10+
/// Sends the current time to the clock.
11+
/// @param time The current time.
912
void tick(string time);
1013
}
1114
}

cpp/IceStorm/clock/Publisher.cpp

Lines changed: 68 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
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

1613
using namespace std;
1714
using 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: " << name << " [--datagram|--twoway|--oneway] [topic]" << endl;
20+
}
2021

2122
int
2223
main(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: " << n << " [--datagram|--twoway|--oneway] [topic]" << endl;
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" << endl;
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." << endl;
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 " << signal << ", exiting..." << endl;
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

Comments
 (0)