Code below is a test program, emulating some events processing. Full code snippets is here. There are 3 threads for event producer, for event distributor like event bus, what handles system event too, and for a certain game, what handles significant events.
And I have stdout printer in event bus, what method pass into every event as a callback. The event bus thread:
class EventBus : public std::enable_shared_from_this<EventBus>
{
using handlers = boost::signals2::signal<void(std::shared_ptr<EventBase>)>;
private:
std::atomic<double> m_GameTicks;
std::thread m_Worker;
std::mutex m_Locker;
std::condition_variable m_NewEvent;
bool m_Suspend;
std::queue<std::shared_ptr<EventBase>> m_EventStorage;
std::unordered_map<std::type_index, handlers> m_Subscribers;
std::shared_ptr<IPrinter> m_InfoPrinter;
public:
EventBus()
{
m_Worker = std::thread([this]() /// Firing event
{
while (true)
{
std::shared_ptr<EventBase> event;
{
std::unique_lock guard(m_Locker);
m_NewEvent.wait(
guard,
[this]{ return m_Suspend || !m_EventStorage.empty(); });
if (m_Suspend && m_EventStorage.empty())
{
break;
}
event = std::move(m_EventStorage.front());
m_EventStorage.pop();
}
auto raw_event = event.get();
try
{
m_Subscribers[typeid(*raw_event)](event);
}
catch (std::exception& ex)
{
std::cerr << ex.what() << std::endl;
std::exit(EXIT_FAILURE);
}
}
});
}
~EventBus()
{
m_Worker.join();
}
AddEvent(std::shared_ptr<EventBase>&& event)
{
event->SetPrintingCallback(
[/*ptr = shared_from_this()*/ this](auto&& message)
{
return m_InfoPrinter->SafetyPrint(
m_GameTicks,
std::forward<decltype(message)>(message));
});
{
std::lock_guard guard(m_Locker);
m_EventStorage.push(std::move(event));
}
m_NewEvent.notify_one();
}
template <typename TEvent, typename TSubscriber> // TODO add enable_if
void Subscribe(const std::shared_ptr<TSubscriber>& subscriber)
{
m_Subscribers[typeid(TEvent)].connect(
[subscriber](std::shared_ptr<EventBase> event)
{
subscriber->ProcessEvent(std::static_pointer_cast<TEvent>(event));
});
}
template <typename TEvent, typename TFunc>
void Subscribe(const TFunc& subscriber_callback)
{
m_Subscribers[typeid(TEvent)].connect(
[subscriber_callback](std::shared_ptr<EventBase> event)
{
subscriber_callback(std::static_pointer_cast<TEvent>(event));
});
}
template <typename TEvent>
void SubscribeSelf()
{
m_Subscribers[typeid(TEvent)].connect(
[this](std::shared_ptr<EventBase> event)
{
ProcessEvent(std::static_pointer_cast<TEvent>(event));
});
}
};
There is SIGSEGV at this variant sometimes of AddEvent, but if I pass shared_form_this, it will be called either never, or sometimes, processed one or two events. But I don't why does it happen, and the first, and the second variant?
I try to debug and I see that boost.signal2 disconnects handlers at the second variant with shared_from_this passing.
The game thread:
class GameMap : public std::enable_shared_from_this<GameMap>
{
public:
GameMap(const MapPoint& map_size, const Key<GameMapFactory>&)
: m_MapSize(map_size)
, m_Work(std::make_unique<dummy_game_work_type>(m_GameContext.get_executor()))
{
m_GameThread = std::thread([this] ()
{
m_GameContext.run();
});
}
~GameMap()
{
m_Work.reset(); // need transfer this to processing finish event?
m_GameThread.join();
}
};
GameMap handles events into ProcessEvent method, does some validation and post it handlers via boost::asio::post for further processing.
The main thread:
int main(int ac, char **av)
{
std::shared_ptr<GameMap> map;
std::shared_ptr<EventBus> bus = std::make_shared<EventBus (std::make_shared<StdOutPrinter>());
bus->Subscribe<MapCreationEvent>(
[&map, &bus](auto&& event) // todo check about references in capture list
{
map = GameMapFactory{}.CreateMap(std::forward<decltype(event)>(event));
bus->Subscribe<MarchEvent>(map);
// todo think about replace this to Game Map Factory
});
bus->Subscribe<SpawnCreatureEvent>(
[](auto&& event)
{
CreatureFactory{}.CreateCreature(std::forward<decltype(event)>(event));
});
// bus->Subscribe<WaitEvent>(bus); // todo it doesn't work too
// bus->Subscribe<WaitEvent>( // todo why it doesn't work subscription to self slot??
// [bus](auto&& event)
// {
// bus->ProcessEvent(std::forward<decltype(event)>(event));
// });
bus->SubscribeSelf<WaitEvent>();
bus->SubscribeSelf<FinishEvent>();
// todo test producer
std::vector<std::shared_ptr<EventBase>> events = {
std::make_shared<MapCreationEvent>(MapPoint(40, 40)),
std::make_shared<SpawnCreatureEvent>(1, MapPoint(40, 40), 50),
std::make_shared<SpawnCreatureEvent>(2, MapPoint(30, 40), 100),
std::make_shared<SpawnCreatureEvent>(3, MapPoint(10, 20), 70),
std::make_shared<SpawnCreatureEvent>(4, MapPoint(40, 30), 90),
std::make_shared<MarchEvent>(1, MapPoint(40, 30)),
std::make_shared<MarchEvent>(2, MapPoint(20, 20)),
std::make_shared<WaitEvent>(1),
std::make_shared<WaitEvent>(1),
std::make_shared<WaitEvent>(1),
std::make_shared<WaitEvent>(1),
std::make_shared<WaitEvent>(1),
std::make_shared<WaitEvent>(1),
std::make_shared<WaitEvent>(1),
std::make_shared<WaitEvent>(1),
std::make_shared<WaitEvent>(1),
std::make_shared<WaitEvent>(1),
std::make_shared<MarchEvent>(4, MapPoint(20, 20)),
std::make_shared<FinishEvent>(),
};
for (auto& ev : events)
{
bus->AddEvent(std::move(ev));
}
}
I caught similar problem here. If I subscribe bus to handling Wait and Finish events via Subscribe, I will get the similar behaviour I wrote above: signals2 disconnect all my slots and stop the program. Why?
Could somebody help me with disconnecting and sigsegv?
I tried to change passing this to shared_from_this but I got only other error
Related
I have a call() method in my code, which based on certain conditions calls specific methods :
call(){
if(a){
methodA();
}
if(b){
methodB();
}
if(c){
methodC();
}
}
In the above scenario, I want to limit concurrent executions for methodC.
How can this be achieved?
What you need here is a Semaphore construct (check the bouncer/night club specification in the example).
// Create the semaphore with 3 slots, where 3 are available.
var bouncer = new Semaphore(3, 3);
call(){
if(a){
methodA();
}
if(b){
methodB();
}
if(c){
// Let a thread execute only after acquiring access (a semaphore to be released).
Bouncer.WaitOne();
methodC();
// This thread is done. Let someone else go for it
Bouncer.Release(1);
}
}
If you want to limit the number of concurrent executions to at most one at a time, then you should use a Lock. In Java it should look like:
final Lock lock = new ReentrantLock();
call() {
if(a) {
methodA();
}
if(b) {
methodB();
}
if(c) {
lock.lock();
try {
methodC();
} finally {
lock.unlock();
}
}
}
If you want to limit the number of concurrent executions to more than one at a time, you can use a Semaphore; here CONCURRENT_CALLS_ALLOWED is an int.
final Semaphore semaphore = new Semaphore(CONCURRENT_CALLS_ALLOWED);
call() {
if(a) {
methodA();
}
if(b) {
methodB();
}
if(c) {
semaphore.aquire();//throws checked exception
try {
methodC();
} finally {
semaphore.release();
}
}
}
I chose to return Task<T> and Task from my objects methods to provide easy consumation by the gui. Some of the methods simply wait for mutex of other kind of waithandles . Is there a way to construct Task from WaitHandle.Wait() so that I don't have to block one treadpool thread for that.
There is a way to do this: you can subscribe to WaitHandle using ThreadPool.RegisterWaitForSingleObject method and wrap it via TaskCompletionSource class:
public static class WaitHandleEx
{
public static Task ToTask(this WaitHandle waitHandle)
{
var tcs = new TaskCompletionSource<object>();
// Registering callback to wait till WaitHandle changes its state
ThreadPool.RegisterWaitForSingleObject(
waitObject: waitHandle,
callBack:(o, timeout) => { tcs.SetResult(null); },
state: null,
timeout: TimeSpan.MaxValue,
executeOnlyOnce: true);
return tcs.Task;
}
}
Usage:
WaitHandle wh = new AutoResetEvent(true);
var task = wh.ToTask();
task.Wait();
As noted by #gordy in the comments of the accepted answer of Sergey Teplyakov, MSDN proposes an implementation with unsubscription of the registered WaitHandle.
I slightly modified it here to support the result of the callback: if the registration has timed out, the task return false. If the signal has been received, the task return true:
public static class ExtensionMethods
{
public static Task<bool> WaitOneAsync(this WaitHandle waitHandle, int timeoutMs)
{
if (waitHandle == null)
throw new ArgumentNullException(nameof(waitHandle));
var tcs = new TaskCompletionSource<bool>();
RegisteredWaitHandle registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(
waitHandle,
callBack: (state, timedOut) => { tcs.TrySetResult(!timedOut); },
state: null,
millisecondsTimeOutInterval: timeoutMs,
executeOnlyOnce: true);
return tcs.Task.ContinueWith((antecedent) =>
{
registeredWaitHandle.Unregister(waitObject: null);
try
{
return antecedent.Result;
}
catch
{
return false;
}
});
}
}
Usage is same as the original answer:
WaitHandle signal = new AutoResetEvent(initialState: false);
bool signaled = await signal.WaitOneAsync(1000);
if (signaled)
{
Console.WriteLine("Signal received");
}
else
{
Console.WriteLine("Waiting signal timed out");
}
I'm using EMDK 2.5 (VS2008 and VC# and .NetCF3.5) Barcode2 class from the library to write a sample application to scan bar codes. I followed the samples available in EMDK namely CS_Barcode2Sample1 project.Every time I hardware trigger the scan the notification "E_SCN_READINCOMPATIBLE" is thrown and not able to retrieve the scanned data. The documentation doesn't say much about the cause of E_SCN_READINCOMPATIBLE notification and no luck from Google search. I tried several options including making use of Symbol.Barcode and the outcome is same.
I also tried EMDK 2.3 but the result is same.
I've pasted the whole code here....
public partial class Form1 : Form
{
private Barcode2 myBarcode2 = null;
public Form1()
{
InitializeComponent();
InitBarcode();
}
public bool InitBarcode()
{
// If the Barcode2 object is already initialized then fail the initialization.
if (myBarcode2 != null)
{
return false;
}
else // Else initialize the reader.
{
try
{
Symbol.Barcode2.Device[] AvailableDevices = Symbol.Barcode2.Devices.SupportedDevices;
if (AvailableDevices.Length == 0)
{
return false;
}
if (AvailableDevices.Length == 1)
{
//get the first available scanner in the list
Symbol.Barcode2.Device MyDevice = AvailableDevices[0];
// Create the reader, based on selected device.
myBarcode2 = new Barcode2(MyDevice);
// Attach a scan notification handler.
//this.myScanNotifyHandler = new Barcode2.OnScanHandler(myBarcode2_ScanNotify);
myBarcode2.OnScan += myBarcode2_ScanNotify;
// Attach a status notification handler.
//this.myStatusNotifyHandler = new Barcode2.OnStatusHandler(myBarcode2_StatusNotify);
myBarcode2.OnStatus += myBarcode2_StatusNotify;
myBarcode2.Config.TriggerMode = TRIGGERMODES.HARD;
// Submit a scan.
myBarcode2.Scan(5000);
}
}
catch (OperationFailureException ex)
{
MessageBox.Show("Exception Raised 1");
return false;
}
catch (InvalidRequestException ex)
{
MessageBox.Show("Exception Raised 2");
return false;
}
catch (InvalidIndexerException ex)
{
MessageBox.Show("Exception Raised 3");
return false;
}
}
return false;
}
private void myBarcode2_ScanNotify(ScanDataCollection scanDataCollection)
{
// Checks if the BeginInvoke method is required because the OnScan delegate is called by a different thread
if (this.InvokeRequired)
{
// Executes the OnScan delegate asynchronously on the main thread
this.BeginInvoke(new Barcode2.OnScanHandler(myBarcode2_ScanNotify), new object[] { scanDataCollection });
}
else
{
// Get ScanData
ScanData scanData = scanDataCollection.GetFirst;
int i;
switch (scanData.Result)
{
case Symbol.Barcode2.Results.SUCCESS:
String str = scanData.Text;
myBarcode2.Config.TriggerMode = TRIGGERMODES.HARD;
myBarcode2.Scan(5000);
break;
case Symbol.Barcode2.Results.E_SCN_READTIMEOUT:
break;
case Symbol.Barcode2.Results.CANCELED:
break;
case Symbol.Barcode2.Results.E_SCN_DEVICEFAILURE:
i = 93;
break;
default:
if (scanData.Result == Symbol.Barcode2.Results.E_SCN_READINCOMPATIBLE)
{
// If the failure is E_SCN_READINCOMPATIBLE, exit the application.
MessageBox.Show("Fatal Error");
this.Close();
return;
}
break;
}
}
}
private void myBarcode2_StatusNotify(StatusData statusData)
{
// Checks if the Invoke method is required because the OnStatus delegate is called by a different thread
if (this.InvokeRequired)
{
// Executes the OnStatus delegate on the main thread
this.Invoke(new Barcode2.OnStatusHandler(myBarcode2_StatusNotify), new object[] { statusData });
}
else
{
int i;
switch (statusData.State)
{
case States.IDLE:
break;
case States.READY:
break;
default:
break;
}
}
}
}
}
I've went thru this recently also, as I observed, it probably due to the scanner device is occupied by other application, where the scan request has been queued already, you can go to memory management, and kill the suspect app, and try your app again.
Refer to the Symbol FAQ
Just wanted to see if this is the right way of doing things:
Thread A {
pthread_lock_mutex(&mutex);
while(flag_set())
pthread_cond_wait(&cond, &mutex);
read_file();
pthread_unlock_mutex(&mutex);
}
Thread B{
pthread_cond_signal( &cond );
}
Sorry, I am quite new to threading.
use Monitor.WAit and Monitor.Pulse
static readonly object _locker = new object();
static void Main()
{
new thread (work1).start();
new thread (work2).start();
}
Static void work1()
{
console.writeline("work1 started");
lock(_locker)
Monitor.Wait(_locker); //here we block the first thread until its signaled from the second thread
console.writeline("work1 wake up");
}
static void work2()
{
console.writeline("work2 will a wake work1");
console.readline();
lock(_locker)
{
Monitor.pulse(_locker); //tell the first thread to continue working
}
}
You can achieve you goal by using another construct -- e.g. ManualResetEvent or AutoResetEvent. Below are C# examples for both:
var resetEvent = new ManualResetEvent(false);
new Timer(o => resetEvent.Set(), null, 1, 500); // Set() is called in another thread
// it unblocks main thread
resetEvent.Reset(); // main thread will be blocked in WaitOne() method
while (true)
{
resetEvent.WaitOne(); // this waits until event is set
resetEvent.Reset(); // immediatelly reset it back
// do something
}
.....
var resetEvent = new AutoResetEvent(false);
new Timer(o => resetEvent.Set(), null, 1, 500); // this is called in another thread
resetEvent.Reset();
while (true)
{
resetEvent.WaitOne();
// do something
}
My somewhat data-intensive wp7 app persists data as follows: I maintain a change journal reflecting all user activity, and every couple of seconds, a thread timer spins up a threadpool thread that flushes the change journal to a database inside a transaction. It looks something like this:
When the user exits, I stop the timer, flush the journal on the UI thread (takes no more than a second or two), and dismount the DB.
However, if the worker thread is active when the user exits, I can't figure out how to react gracefully. The system seems to kill the worker thread, so it never finishes its work and never gives up its lock on the database connection, and the ui thread then attempts to acquire the lock, and is immediately killed by the system. I tried setting a flag on the UI thread requesting the worker to abort, but I think the worker was interrupted before it read the flag. Everything works fine except for this 1 in 100 scenario where some user changes end up not being saved to the db, and I can't seem to get around this.
Very simplified code below:
private Timer _SweepTimer = new Timer(SweepCallback, null, 5000, 5000);
private volatile bool _BailOut = false;
private void SweepCallback(object state) {
lock (db) {
db.startTransaction();
foreach(var entry in changeJournal){
//CRUD entry as appropriate
if(_BailOut){
db.rollbackTransaction();
return;
}
}
db.endTransaction();
changeJournal.Clear();
}
}
private void RespondToSystemExit(){
_BailOut = true; //Set flag for worker to exit
lock(db){ //In theory, should acquire the lock after the bg thread bails out
SweepCallback(null);//Flush to db on the UI thread
db.dismount();//App is now ready to close
}
}
Well, just to close this question, I ended up using a manualresetevent instead of the locking, which is to the best of my understanding a misuse of the manualresetevent, risky and hacky, but its better than nothing.
I still don't know why my original code wasn't working.
EDIT: For posterity, I'm reposting the code to reproduce this from the MS forums:
//This is a functioning console app showing the code working as it should. Press "w" and then "i" to start and then interrupt the worker
using System;
using System.Threading;
namespace deadlocktest {
class Program {
static void Main(string[] args) {
var tester = new ThreadTest();
string input = "";
while (!input.Equals("x")) {
input = Console.ReadLine();
switch (input) {
case "w":
tester.StartWorker();
break;
case "i":
tester.Interrupt();
break;
default:
return;
}
}
}
}
class ThreadTest{
private Object lockObj = new Object();
private volatile bool WorkerCancel = false;
public void StartWorker(){
ThreadPool.QueueUserWorkItem((obj) => {
if (Monitor.TryEnter(lockObj)) {
try {
Log("Worker acquired the lock");
for (int x = 0; x < 10; x++) {
Thread.Sleep(1200);
Log("Worker: tick" + x.ToString());
if (WorkerCancel) {
Log("Worker received exit signal, exiting");
WorkerCancel = false;
break;
}
}
} finally {
Monitor.Exit(lockObj);
Log("Worker released the lock");
}
} else {
Log("Worker failed to acquire lock");
}
});
}
public void Interrupt() {
Log("UI thread - Setting interrupt flag");
WorkerCancel = true;
if (Monitor.TryEnter(lockObj, 5000)) {
try {
Log("UI thread - successfully acquired lock from worker");
} finally {
Monitor.Exit(lockObj);
Log("UI thread - Released the lock");
}
} else {
Log("UI thread - failed to acquire the lock from the worker");
}
}
private void Log(string Data) {
Console.WriteLine(string.Format("{0} - {1}", DateTime.Now.ToString("mm:ss:ffff"), Data));
}
}
}
Here is nearly identical code that fails for WP7, just make a page with two buttons and hook them
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows;
using Microsoft.Phone.Controls;
namespace WorkerThreadDemo {
public partial class MainPage : PhoneApplicationPage {
public MainPage() {
InitializeComponent();
}
private Object lockObj = new Object();
private volatile bool WorkerCancel = false;
private void buttonStartWorker_Click(object sender, RoutedEventArgs e) {
ThreadPool.QueueUserWorkItem((obj) => {
if (Monitor.TryEnter(lockObj)) {
try {
Log("Worker acquired the lock");
for (int x = 0; x < 10; x++) {
Thread.Sleep(1200);
Log("Worker: tick" + x.ToString());
if (WorkerCancel) {
Log("Worker received exit signal, exiting");
WorkerCancel = false;
break;
}
}
} finally {
Monitor.Exit(lockObj);
Log("Worker released the lock");
}
} else {
Log("Worker failed to acquire lock");
}
});
}
private void Log(string Data) {
Debug.WriteLine(string.Format("{0} - {1}", DateTime.Now.ToString("mm:ss:ffff"), Data));
}
private void buttonInterrupt_Click(object sender, RoutedEventArgs e) {
Log("UI thread - Setting interrupt flag");
WorkerCancel = true;
//Thread.Sleep(3000); UNCOMMENT ME AND THIS WILL START TO WORK!
if (Monitor.TryEnter(lockObj, 5000)) {
try {
Log("UI thread - successfully acquired lock from worker");
} finally {
Monitor.Exit(lockObj);
Log("UI thread - Released the lock");
}
} else {
Log("UI thread - failed to acquire the lock from the worker");
}
}
}
}
Your approach should work when you operate from the Application_Deactivated or Application_Closing event. MSDN says:
There is a time limit for the Deactivated event to complete. The
device may terminate the application if it takes longer than 10
seconds to save the transient state.
So if you say it just takes just a few seconds this should be fine. Unless the docs don't tell the whole story. Or your worker thread takes longer to exit than you think.
As Heinrich Ulbricht already said you have <=10 sec to finish your stuff, but you should block MainThread to get them.
It means that even if you have BG thread with much work to do, but your UI thread just does nothing in OnClosingEvent/OnDeactivatingEvent - you will not get your 10 seconds.
Our application actually does eternal wait on UI thread in closing event to allow BG thread send some data thru sockets.