{"id":20217372,"url":"https://github.com/windowsnt/mt","last_synced_at":"2025-04-10T15:43:03.509Z","repository":{"id":80700407,"uuid":"158881474","full_name":"WindowsNT/mt","owner":"WindowsNT","description":"tlock, RWMUTEX, Collab, USM, RSem and other C++ templates for Windows to provide read/write mutex locks, various multithreading tools, collaboration, differential updates and more","archived":false,"fork":false,"pushed_at":"2020-02-08T13:28:10.000Z","size":6245,"stargazers_count":34,"open_issues_count":1,"forks_count":18,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-03-24T13:21:29.047Z","etag":null,"topics":["concurrency","concurrent-programming","lock","mutex","thread","tlock","win32","write-locks"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WindowsNT.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-23T22:00:47.000Z","updated_at":"2024-08-22T03:29:25.000Z","dependencies_parsed_at":null,"dependency_job_id":"fa7c2322-7a66-4db5-adb1-a63214cacdfb","html_url":"https://github.com/WindowsNT/mt","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WindowsNT%2Fmt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WindowsNT%2Fmt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WindowsNT%2Fmt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WindowsNT%2Fmt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WindowsNT","download_url":"https://codeload.github.com/WindowsNT/mt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248243497,"owners_count":21071054,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["concurrency","concurrent-programming","lock","mutex","thread","tlock","win32","write-locks"],"created_at":"2024-11-14T06:33:50.142Z","updated_at":"2025-04-10T15:43:03.499Z","avatar_url":"https://github.com/WindowsNT.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Multithreading Tools for Windows\n\n\n# tlock\nA C++ library for Windows for efficient read/write locks with template generalization.\n\nBased on my tlock article (https://www.codeproject.com/Articles/1186797/tlock-Any-Cplusplus-object-read-write-thread-safe)\nBased on my RWMutex (https://www.codeproject.com/Articles/1053865/RWMutex-A-Shared-Exclusive-Recursive-Mutex)\nAnd now, tlock2\u003c\u003e which uses shared_mutex, no Windows dependency.\n\nQuick example:\n\n```C++\ntlock\u003cvector\u003cint\u003e\u003e s;\ntlock2\u003cvector\u003cint\u003e\u003e s;\n```\n\nThis allows you to use a vector\u003cint\u003e in a form of lockable object.\n\n```C++\ns.writelock([\u0026](vector\u003cint\u003e\u0026 ss)\n    {\n    ss.push_back(100);\n    ss.push_back(150); \n    ss.erase(ss.begin());\n    // Safe operations, s is locked while in this function. s.readlock() would block.\n    })\n```\n\n\n```C++\ns.readlock([\u0026](const vector\u003cint\u003e\u0026 ss)\n    {\n \n    });\n```\n\nOr you can use direct calls:\n\n```C++\ntlock\u003cvector\u003cint\u003e\u003e s;\nstd::thread t1([\u0026]() { s-\u003epush_back(0); });\nstd::thread t2([\u0026]() { s-\u003epush_back(1); });\nstd::thread t3([\u0026]() { s-\u003epush_back(2); });\nstd::thread t4([\u0026]() { s-\u003epush_back(3); });\nstd::thread t5([\u0026]() { s-\u003epush_back(4); });\nt1.join();t2.join(); t3.join(); t4.join(); t5.join();\n```\n\n\nThe r() method is called when you want read-only access to the object. This is the default when operator -\u003e is called on a const object. Many threads can call r() simultaneously.\n\nThe w() method is called when you want write access to the object. This is the default for operator -\u003e if the object is not constant. w() blocks until all threads that are within r() return, and then does not allow any other thread to complete r() or w() until it returns.\n\nThe readlock() method is called when you want many operations in a locked read-only object, so it calls your function, passing a reference to the constant, locked object.\n\nThe writelock() method is called when you want many operations in a locked read-write object, so it calls your function, passing a reference to the locked object.\n\nYou can also use tlock upgrade function\n\n```C++\ns.rwlock([\u0026](const vector\u003cint\u003e\u0026 vv, std::function\u003cvoid(std::function\u003cvoid(vector\u003cint\u003e\u0026)\u003e)\u003e upgrfunc) \n{\n\t// vv read access\n\tupgrfunc([\u0026](vector\u003cint\u003e\u0026 nn) \n\t{\n\t\t// nn write access\n\t\t// function end downgrades\n\t});\n});\n```\n\nYou can also use my RWMUTEX functions\n\n```C++\nRWMUTEX m;\nvoid foo1()\n{\n  RWMUTEXLOCKREAD lock(\u0026m);\n  // while in here, m is read-locked\n}\n\nvoid foo2()\n{\n  RWMUTEXLOCKWRITE lock(\u0026m);\n  // while in here, m is write-locked\n}\n\nvoid foo3()\n{\n  RWMUTEXLOCKREADWRITE lock(\u0026m);\n  // while in here, m is read-locked\n  \n  ...\n  m.Upgrade(); // now m is write-locked\n  ...\n  m.Downgrade(); // m back read-locked\n  \n  // end of function, m released\n}\n\n\n```\n\n# cow\nA copy on write class that automatically duplicates an object when writing.\n\n```C++\n    struct FOO\n    {\n\t    int a1 = 0;\n\t    int a2 = 0;\n    };\n\n\tstd::shared_ptr\u003cFOO\u003e x = std::make_shared\u003cFOO\u003e();\n\t// read only\n\tcow\u003cFOO\u003e c(x);\n\tconst FOO\u0026 j1 = *c;\n\tcow\u003cFOO\u003e c2 = c;\n\n\t// Write\n\tc-\u003ea2 = 2; // 1 copy \n\tc-\u003ea1 = 4; // No copy, because only one reference count optimization. \n\n\tc2.write([](std::shared_ptr\u003cFOO\u003e t) // Aopy, now there are 3 smart pointers with count 1\n\t\t{\n\t\t\tt-\u003ea1 = 10;\n\t\t\tt-\u003ea2 = 20;\n\t\t});\n\n\n```\n# Collaboration Tools\nWelcome to my collaboration tools for Windows.\n\n## Diff Lib\nArticle: https://www.codeproject.com/Articles/861419/DIFF-Your-IRdcLibrary-API-for-Remote-Differential\n\nA library to implement incremental updates to data.\n\n```C++\n// Say that hX1 and hX2 are handles to an original file and a newer file\nCComPtr\u003cIRdcFileReader\u003e fil1;\nCComPtr\u003cIRdcFileReader\u003e fil2;\nfil1.Attach(new DIFF::FileRdcFileReader(hX1));\nfil2.Attach(new DIFF::FileRdcFileReader(hX2));\n\n// Instantiate the library\nDIFF::DIFF d;\n\n// Create a signature for both files\nDIFF::FileDiffWriter sig1(hS1);\nDIFF::FileDiffWriter sig2(hS2);\nd.GenerateSignature(fil1,sig1);\nd.GenerateSignature(fil2,sig1);\n\n// Generate diff between old and new file\nCComPtr\u003cIRdcFileReader\u003e xsig1;\nCComPtr\u003cIRdcFileReader\u003e xsig2;\nsig1.GetReader(\u0026xsig1);\nsig2.GetReader(\u0026xsig2);\nDIFF::MemoryDiffWriter diff1_2_sc;\nd.GenerateDiff(xsig1,xsig2,r2,diff1_2_sc));\n\n // Recreate the new file based on the old file and the diff\nDIFF::FileDiffWriter reco1(hX3);\nd.Reconstruct(r1,xdiff1,0,reco1);\n\n```\n\n## ThreadPool API\nArticle: https://www.codeproject.com/Articles/1012843/Win-Thread-Pools-and-Cplusplus-A-quick-wrapper\n\n\n\n## Shared Memory\nArticle: https://www.codeproject.com/Articles/835818/Ultimate-Shared-Memory-A-flexible-class-for-sharin\n\n```C++\n\n// Process 1\nusm\u003cchar\u003e sm1(L\"{4BF41A4E-ACF9-4E1D-A479-14DE9FF83BC2}\", false, 1000, 2);\nsm1.Initialize();\n\n// Process 2\nusm\u003cchar\u003e sm2(L\"{4BF41A4E-ACF9-4E1D-A479-14DE9FF83BC2}\", false, 1000, 2);\nsm2.Initialize();\n\n// Process 1\nsm1.WriteData(\"Hello\", 5, 0, 0);\n\n// Process 2\nchar r[10] = { 0 };\nsm2.ReadData(r, 5, 0, 0);\n\n// r must contain \"Hello\"\n```\n\n## FileSnap\nArticle: https://www.codeproject.com/Articles/1209648/FileSnap-A-Windows-library-for-differential-file-s\n\n```C++\n\nclass FILESNAP\n{\npublic:\n    struct alignas(8)  FSITEM\n    {\n        CLSID cid = FILESNAP::GUID_HEADER;\n        unsigned long long DiffAt = 0; \n        FILETIME created = ti();\n        FILETIME updated = ti();\n        unsigned long long i = 0;\n        unsigned long long at = 0;\n        unsigned long long sz = 0;\n        unsigned long long extradatasize = 0;\n    };\n\n    inline bool BuildMap(vector\u003cFSITEM\u003e\u0026 fsx);\n    FILESNAP(const wchar_t* fi);\n    inline bool SetSnap(size_t idx,int CommitForce = 0);\n    inline bool Create(DWORD Access= GENERIC_READ | GENERIC_WRITE, DWORD Share = 0, \n          LPSECURITY_ATTRIBUTES Atrs = 0, DWORD Disp = CREATE_NEW, DWORD Flags = 0);\n    inline unsigned long long Size();\n    inline bool Finalize();\n    inline bool Commit(size_t At,int Mode);\n    inline HANDLE GetH();\n    inline BOOL Write(const char* d, unsigned long long sz2);\n    inline BOOL Read(char* d, unsigned long long sz2);\n    inline unsigned long long SetFilePointer(unsigned long long s, DWORD m = FILE_BEGIN);\n    inline BOOL SetEnd();\n    inline void Close();\n};\n\n\n```\n\n* You want to create a new file, you simply pass the name to the FILESNAP constructor.\n* You call Create() with the CreateFile flag CREATE_NEW to create the file.\n* You write to the file using Write().\n* When you want to save the current version, you call Commit(0,0). For the first save, Commit() ignores the two parameters.\n* You keep writing to the file using Write().\n* The next Commit() call will save the current contents as a differential backup. If the Mode parameter is 0, then Commit() saves as a differential backup to the first commit always. If the Mode parameter is 1, then Commit() saves as a differential backup to the specified commit number as the At parameter. This allows you to either use differential or incremental backups.\n* You keep writing, reading or else to the current handle using the Read(), Write(), SetEnd(), SetFilePointer(), Size() and GetH() function which returns the current HANDLE that you can use in other file functions.\n* If you want to revert to a specific saving, use SetSnap. CommitForce can be 0, 1 or 2: 0 means that if the file exists already, the function fails, 1 means that if the file exists already, a commit is taken before reverting, 2 does not commit before reverting.\n* After you have used SetSnap(), Read()/Write()/GetH() etc. operate on the reverted data.\n* Close() will close the file (it does not commit), and delete all temporary files used by the class.\n \nWhen you open an existing file, the class automatically calls SetSnap() on the last snapshot found in the file. You can call BuildMap() to return a FSITEM array of all snapshots included in the file.\n\nIf you build files with mostly differential backups (related to the first snapshot), then the file will be larger, but quicker to open because only one operation will be done (the comparison between the first and the opened snapshot).\nIf you build files with mostly incremental backups (related to the last snapshot), then the file will be smaller, but slower to open because all snapshots must be processed when a snapshot is loaded.\n\n## Real time collaboration\nArticle: https://www.codeproject.com/Articles/1158754/Real-time-collaboration-A-quick-Cplusplus-Windows\n\nServer Setup:\n\n```C++\nCOLLAB::ANYAUTH auth;\nCOLLAB::SERVER s(\u0026auth, 8765,true); // Port 8765, and true to use filesystem instead of in-memory docs\ns.Start(); // Start the server\n...\n...\n...\ns.End(); // Ends the server when we want to close it\n```\n\nClient Setup:\n```C++\n\n//\nclass ON\n    {\n    public:\n        virtual void Update(CLSID cid,const char* d,size_t sz) = 0;\n    };\n\n// Reconstruct from an ON update\nvoid RecoFromDiff(const char* d, size_t sz, const char* e, size_t sze, vector\u003cchar\u003e\u0026 o)\n    {\n    DIFFLIB::DIFF diff;\n    DIFFLIB::MemoryRdcFileReader r1(e, sze);\n    DIFFLIB::MemoryRdcFileReader diffi(d, sz);\n\n    DIFFLIB::MemoryDiffWriter dw;\n    diff.Reconstruct(\u0026r1, \u0026diffi, 0, dw);\n    o = dw.p();\n    }\n\nCOLLAB::ANYAUTH auth;\nCOLLAB::CLIENT c1(\u0026auth);\nMYON on; // some class that implements Update() of COLLAB::ON \nc1.AddOn(\u0026on); // check below for ON class\nc1.Connect(\"localhost\",8765);\nc1.Open(DOCUMENT_GUID); // If guid does not exist, server creates such a document\n//\n...\n...\n...\nc1.Close(DOCUMENT_GUID);\n...\n...\n...\nc1.RemoveOn(\u0026on);\nc1.Disconnect();\n\n// Put updates to the server\nHRESULT Put(GUID g, const char* d,size_t sz);\n\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwindowsnt%2Fmt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwindowsnt%2Fmt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwindowsnt%2Fmt/lists"}