Read histogram from TFile while actively writing to it (with example)

@pcanal : I determined the cause of the segfault was calling Draw() on the TH1I pointer that was still NULL.

I realize now my issue with

        delete file->FindObject(name);
        file->ReadKeys();

These commands only work if you have loaded the ROOT file that is actively being written. This does not work if you have opened an old file of the same name. When the file is RECREATEd,

I now have two working methods of reading a file from disk while a process is actively writing to it. Below I post both the example, and steps to run. I will mark the topic as solved.

Working Example

///@file example-28273.C
///@brief A program that will generate data and asynchronously write it to disk.
///@author S. V. Paulauskas
///@date March 12, 2018
///@copyright Copyright (c) 2018 S. V. Paulauskas.
///@copyright All rights reserved. Released under the Creative Commons Attribution-ShareAlike 4.0 International License
#include <TFile.h>
#include <TH1D.h>

#include <iostream>
#include <mutex>
#include <thread>

void AsyncFlush(TFile *file, std::mutex *lock, unsigned int *loopId) {
    std::cout << "AsyncFlush - Now calling file->Write" << std::endl;
    file->Write(0, TObject::kWriteDelete);
    std::cout << "AsyncFlush - Now unlocking the file for writing in loop " << *loopId << std::endl;
    lock->unlock();
}

void WriteToDisk(TFile *file, unsigned int *loopID, std::mutex *lock) {
    if (lock->try_lock()) {
        std::cout << "WriteToDisk - we're creating the new thread in loop number " << *loopID << endl;
        std::thread worker0(AsyncFlush, file, lock, loopID);
        worker0.detach();
    }
}

void GenerateHistogram() {
    std::mutex lock;
    TFile *f = new TFile("test.root", "RECREATE");
    TH1D *hist = new TH1D("hist", "", 100, -2, 2);
    unsigned int loopCounter = 0;
    while (loopCounter < 40000) {
        hist->FillRandom("gaus", 10000);
        WriteToDisk(f, &loopCounter, &lock);
        loopCounter++;
    }
    while(!lock.try_lock())
        sleep(1);
    f->Write(nullptr, TObject::kWriteDelete);
    f->Close();
}

// Adapted from
// https://root-forum.cern.ch/t/read-a-tfile-while-writing-with-another-process/18608/6
// and follow up comment
// https://root-forum.cern.ch/t/read-histogram-tree-from-tfile-while-actively-writing-to-it/28273/10
void ReadHistogram(TFile *file, const char *name = "hist") {
    TH1D *hist1 = nullptr;
    delete file->FindObject(name);
    file->ReadKeys();
    file->GetObject(name, hist1);
    if(hist1)
       hist1->Draw();
}

// Adapted from
// https://root-forum.cern.ch/t/read-a-tfile-while-writing-with-another-process/18608/7
void ReadHistogram() {
    TFile *file = TFile::Open("test.root");
    TH1D *hist = nullptr;
    file->GetObject("hist", hist);
    if(hist)
        hist->Draw();
}

Instructions for Running Script

Terminal A - The Writer

user@localhost:> root
root [0] .L example.C+;
root [1] GenerateHistogram();

Terminal B - The Reader

user@localhost:> root
root [0] .L example_C.so;
root [1] ReadHistogram();
root [2] ReadHistogram();
root [3] ReadHistogram();
...

Terminal C - The Reader (alternate)

Executed after Writing has started in Terminal A

user@localhost:> root test.root
root [0] .L example_C.so;
root [1] ReadHistogram(_file0);
root [2] ReadHistogram(_file0);
root [3] ReadHistogram(_file0);
...