{"id":26800495,"url":"https://github.com/ktsu-dev/invoker","last_synced_at":"2026-02-16T07:17:55.867Z","repository":{"id":283211309,"uuid":"951039271","full_name":"ktsu-dev/Invoker","owner":"ktsu-dev","description":null,"archived":false,"fork":false,"pushed_at":"2026-02-14T01:50:38.000Z","size":243,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-14T08:51:25.229Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/ktsu-dev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.md","dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":"COPYRIGHT.md","agents":null,"dco":null,"cla":null}},"created_at":"2025-03-19T04:25:46.000Z","updated_at":"2026-02-14T01:49:31.000Z","dependencies_parsed_at":"2025-04-26T08:20:49.436Z","dependency_job_id":"201ccd0e-16b6-4c21-a552-233b03c62894","html_url":"https://github.com/ktsu-dev/Invoker","commit_stats":null,"previous_names":["ktsu-dev/invoker"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/ktsu-dev/Invoker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ktsu-dev%2FInvoker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ktsu-dev%2FInvoker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ktsu-dev%2FInvoker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ktsu-dev%2FInvoker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ktsu-dev","download_url":"https://codeload.github.com/ktsu-dev/Invoker/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ktsu-dev%2FInvoker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29502934,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-16T05:57:17.024Z","status":"ssl_error","status_checked_at":"2026-02-16T05:56:49.929Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2025-03-29T20:17:39.174Z","updated_at":"2026-02-16T07:17:55.853Z","avatar_url":"https://github.com/ktsu-dev.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ktsu.Invoker\n\n\u003e A .NET library that ensures delegates are executed on the intended thread, simplifying thread management in UI and graphics applications.\n\n[![License](https://img.shields.io/github/license/ktsu-dev/Invoker)](https://github.com/ktsu-dev/Invoker/blob/main/LICENSE.md)\n[![NuGet](https://img.shields.io/nuget/v/ktsu.Invoker.svg)](https://www.nuget.org/packages/ktsu.Invoker/)\n[![NuGet Downloads](https://img.shields.io/nuget/dt/ktsu.Invoker.svg)](https://www.nuget.org/packages/ktsu.Invoker/)\n[![Build Status](https://github.com/ktsu-dev/Invoker/workflows/build/badge.svg)](https://github.com/ktsu-dev/Invoker/actions)\n[![GitHub Stars](https://img.shields.io/github/stars/ktsu-dev/Invoker?style=social)](https://github.com/ktsu-dev/Invoker/stargazers)\n\n## Introduction\n\nInvoker is a .NET library that provides methods to ensure delegates are executed on the intended thread. It is designed to simplify task execution and thread management in .NET applications where delegates are required to run within a specific context, such as the UI thread in WPF or WinForms applications, or the window thread in OpenGL or DirectX applications.\n\n## Features\n\n- **Thread-Safe Execution**: Ensure delegates run on the intended thread\n- **Synchronous \u0026 Asynchronous Support**: Both blocking and non-blocking invocation patterns\n- **Return Value Support**: Easily retrieve results from cross-thread operations\n- **Immediate Execution**: Auto-detect if already on the target thread for optimal performance\n- **Queue Management**: Built-in task queue with controlled execution timing\n- **Thread Ownership**: Clear ownership model for execution contexts\n- **Exception Propagation**: Properly propagates exceptions across thread boundaries\n- **Lightweight Design**: Minimal overhead for performance-critical applications\n\n## Installation\n\n### Package Manager Console\n\n```powershell\nInstall-Package ktsu.Invoker\n```\n\n### .NET CLI\n\n```bash\ndotnet add package ktsu.Invoker\n```\n\n### Package Reference\n\n```xml\n\u003cPackageReference Include=\"ktsu.Invoker\" Version=\"x.y.z\" /\u003e\n```\n\n## Usage Examples\n\n### Basic Example\n\n```csharp\n// Initialize an instance on the owning thread\nvar invoker = new Invoker();\n\n// Queue a task from a different thread, which blocks until the delegate has been executed via DoInvokes() on the owning thread\ninvoker.Invoke(() =\u003e Console.WriteLine(\"Hello, World!\"));\n\n// Call DoInvokes() on the owning thread to execute queued tasks\ninvoker.DoInvokes();\n\n// NOTE: If you queue from the owning thread the delegate will be executed immediately, bypassing DoInvokes()\n\n// Delegates with return values are supported\nstring result = invoker.Invoke(() =\u003e \"Hello, World!\");\n```\n\n### WPF UI Thread Example\n\n```csharp\nusing System.Windows;\nusing ktsu.Invoker;\n\npublic partial class MainWindow : Window\n{\n    private readonly Invoker _invoker = new Invoker();\n    \n    public MainWindow()\n    {\n        InitializeComponent();\n        \n        // Start a background operation\n        Task.Run(() =\u003e BackgroundOperation());\n    }\n    \n    private async Task BackgroundOperation()\n    {\n        // Simulate work\n        await Task.Delay(1000);\n        \n        // Update UI from background thread safely\n        _invoker.Invoke(() =\u003e {\n            StatusTextBlock.Text = \"Operation Completed!\";\n            ResultListBox.Items.Add(\"Background task result\");\n        });\n    }\n    \n    // Call this in your UI event loop or dispatcher\n    private void ProcessEvents()\n    {\n        _invoker.DoInvokes();\n    }\n}\n```\n\n### Asynchronous Invocation\n\n```csharp\nusing ktsu.Invoker;\n\n// Create invoker on the main thread\nvar invoker = new Invoker();\n\n// From background thread\nawait Task.Run(async () =\u003e {\n    // Queue task and continue without waiting\n    invoker.BeginInvoke(() =\u003e Console.WriteLine(\"Processing in the background\"));\n    \n    // Queue task and get Task for completion\n    Task\u003cstring\u003e resultTask = invoker.InvokeAsync(() =\u003e \"Result from main thread\");\n    \n    // Await the result\n    string result = await resultTask;\n    Console.WriteLine($\"Got result: {result}\");\n});\n\n// On main thread, execute pending operations\ninvoker.DoInvokes();\n```\n\n### Game Loop Integration\n\n```csharp\nusing ktsu.Invoker;\n\npublic class Game\n{\n    private readonly Invoker _invoker = new Invoker();\n    \n    public void Run()\n    {\n        // Start rendering on the main thread\n        while (true)\n        {\n            // Execute any queued operations from other threads\n            _invoker.DoInvokes();\n            \n            // Perform rendering\n            Render();\n            \n            // Process events, etc.\n        }\n    }\n    \n    private void Render() \n    {\n        // OpenGL/DirectX rendering code here\n    }\n    \n    // Call this from other threads\n    public void QueueTextureLoad(string texturePath)\n    {\n        // OpenGL/DirectX resources often need to be created on the main thread\n        _invoker.BeginInvoke(() =\u003e LoadTextureOnMainThread(texturePath));\n    }\n    \n    private void LoadTextureOnMainThread(string texturePath)\n    {\n        // Load texture using OpenGL/DirectX APIs\n    }\n}\n```\n\n## API Reference\n\n### `Invoker` Class\n\nThe main class that manages execution of delegates on the intended thread.\n\n#### Properties\n\n| Name | Type | Description |\n|------|------|-------------|\n| `IsInvokerThread` | `bool` | Returns true if the current thread is the thread that owns the invoker |\n| `HasPendingInvokes` | `bool` | Returns true if there are any pending invocations waiting to be processed |\n\n#### Methods\n\n| Name | Parameters | Return Type | Description |\n|------|------------|-------------|-------------|\n| `Invoke\u003cT\u003e` | `Func\u003cT\u003e func` | `T` | Executes the function on the owner thread and returns its result, blocking if called from another thread |\n| `Invoke` | `Action action` | `void` | Executes the action on the owner thread, blocking if called from another thread |\n| `BeginInvoke` | `Action action` | `void` | Queues an action to be executed on the owner thread without waiting for completion |\n| `InvokeAsync\u003cT\u003e` | `Func\u003cT\u003e func` | `Task\u003cT\u003e` | Queues a function to be executed on the owner thread and returns a Task that completes with the result |\n| `InvokeAsync` | `Action action` | `Task` | Queues an action to be executed on the owner thread and returns a Task that completes when the action is done |\n| `DoInvokes` | | `void` | Processes all pending invocations (must be called from the owner thread) |\n\n## Advanced Usage\n\n### Thread Synchronization\n\nInvoker provides a clean way to synchronize access to resources that must be accessed from a specific thread:\n\n```csharp\npublic class ResourceManager\n{\n    private readonly Invoker _invoker = new Invoker();\n    private readonly Dictionary\u003cstring, Resource\u003e _resources = new Dictionary\u003cstring, Resource\u003e();\n    \n    // This method can be called from any thread\n    public Resource GetResource(string id)\n    {\n        return _invoker.Invoke(() =\u003e {\n            if (!_resources.TryGetValue(id, out var resource))\n            {\n                resource = new Resource(id);\n                _resources[id] = resource;\n            }\n            return resource;\n        });\n    }\n    \n    // Call this regularly on the owner thread\n    public void Update()\n    {\n        _invoker.DoInvokes(); // Process any pending resource requests\n        \n        // Update resources\n        foreach (var resource in _resources.Values)\n        {\n            resource.Update();\n        }\n    }\n}\n```\n\n### Custom Thread Identification\n\nSometimes you may need custom thread identification logic:\n\n```csharp\npublic class CustomInvoker : Invoker\n{\n    private readonly int _targetThreadId;\n    \n    public CustomInvoker(int targetThreadId)\n    {\n        _targetThreadId = targetThreadId;\n    }\n    \n    // Override to provide custom thread identification\n    protected override bool IsOwnerThread()\n    {\n        return Thread.CurrentThread.ManagedThreadId == _targetThreadId;\n    }\n}\n```\n\n## Contributing\n\nContributions are welcome! Here's how you can help:\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\nPlease make sure to update tests as appropriate and adhere to the existing coding style.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.\n\n## Acknowledgements\n\nSpecial thanks to all contributors and the .NET community for their support.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fktsu-dev%2Finvoker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fktsu-dev%2Finvoker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fktsu-dev%2Finvoker/lists"}