में प्रबंधित धागे और फाइबर का उपयोग करना ठीक है, निम्न लिंक में एक चेतावनी है कि चर्चा असमर्थित और अनियंत्रित एपिस का उपयोग करती है। खैर मैं किसी भी तरह से कोड नमूना का उपयोग करने की कोशिश कर रहा हूँ। यह ज्यादातर काम करता है। अपवादों से संबंधित विशिष्ट मुद्दे के बारे में कोई विचार?सीएलआर
http://msdn.microsoft.com/en-us/magazine/cc164086.aspx
FYI करें, मैं मूल नमूना के ऊपर एक सुधार कर दिया। यह "पिछला फाइबर" के लिए एक सूचक बनाए रख रहा था। इसके बजाए, नीचे दिया गया नमूना एक "मेनफाइबर" पॉइंटर का उपयोग करता है जो हर फाइबर वर्ग को पास हो जाता है। इस तरह, वे हमेशा मुख्य फाइबर पर वापस आते हैं। इससे मुख्य फाइबर अन्य सभी फाइबर के लिए शेड्यूलिंग को संभालने की अनुमति देता है। अन्य फाइबर हमेशा मुख्य फाइबर को "उपज" देते हैं।
इस प्रश्न को पोस्ट करने का कारण एक फाइबर के अंदर अपवाद फेंकने के साथ करना है। लेख के मुताबिक, CreateLogicalThreadState(), SwitchOutLogicalThreadState(), आदि के साथ CorBindToRunTime API का उपयोग करके, फ्रेमवर्क प्रत्येक फाइबर के लिए एक प्रबंधित थ्रेड बनाएगा और अपवादों को सही तरीके से संभाल देगा।
हालांकि, शामिल कोड उदाहरणों में इसमें एक यूनीट परीक्षण है जो एक फाइबर के भीतर एक प्रबंधित अपवाद फेंकने और उसी फाइबर के भीतर इसे पकड़ने के साथ प्रयोग करता है। काम के नरम। लेकिन एक संदेश लॉग इन करके इसे संभालने के बाद, ऐसा लगता है कि ढेर खराब स्थिति में है क्योंकि अगर फाइबर किसी अन्य विधि को एक खाली विधि भी कहता है, तो पूरा एप्लिकेशन क्रैश हो जाता है।
यह मेरा तात्पर्य है कि SwitchOutLogicalThreadState() और SwitchInLogicalThreadState() शायद ठीक से उपयोग नहीं किया जा रहा है या अन्यथा वे अपना काम नहीं कर रहे हैं।
नोट: समस्या का एक संकेत यह है कि प्रबंधित कोड Thread.CurrentThread.ManagedThreadId लॉग करता है और यह प्रत्येक फाइबर के लिए समान है। इससे पता चलता है कि CreateLogicalThreadState() विधि वास्तव में विज्ञापित के रूप में एक नया प्रबंधित धागा नहीं बना था।
इस बेहतर विश्लेषण के लिए, मैंने फाइबर को संभालने के लिए बुलाए गए निम्न स्तर के एपीआई के क्रम की छद्म कोड सूची बनाई है। याद रखें, कि फाइबर सभी एक ही थ्रेड पर चलते हैं, इसलिए कुछ भी नहीं हो रहा है, यह एक रैखिक तर्क है। निश्चित रूप से आवश्यक चाल स्टैक को सहेजना और पुनर्स्थापित करना है। ऐसा लगता है कि ऐसा लगता है कि परेशानी हो रही है।
यह पता के रूप में सिर्फ एक धागा ऐसा है तो यह एक फाइबर में धर्मान्तरित शुरू होता है:
- ConvertThreadToFiber (objptr);
- CreateFiber() // कई win32 फाइबर बनाएं।
अब एक फाइबर पहली बार आह्वान, यह स्टार्टअप विधि करता है:
- corhost-> SwitchOutLogicalThreadState (& कुकी); स्टैक पर आयोजित मुख्य कुकी है।
- SwitchToFiber(); // पहली बार फाइबर स्टार्टअप विधि
- corhost-> CreateLogicalThreadState();
- मुख्य फाइबर सार विधि चलाएं।
अंततः फाइबर मुख्य फाइबर के लिए वापस उपज के लिए की जरूरत है:
- corhost-> SwitchOutLogicalThreadState (& कुकी);
- स्विचटोफाइबर (फाइबर);
- corhost-> SwitchInLogicalThreadState (कुकी); // मुख्य फाइबर कुकी, है ना?
इसके अलावा मुख्य फाइबर एक पहले से मौजूद फाइबर फिर से शुरू होगा:
- corhost-> SwitchOutLogicalThreadState (& कुकी);
- स्विचटोफाइबर (फाइबर);
- corhost-> SwitchInLogicalThreadState (& कुकी); // मुख्य फाइबर कुकी, है ना?
निम्नलिखित fibers.cpp है जो प्रबंधित कोड के लिए फाइबर एपीआई को लपेटता है।
#define _WIN32_WINNT 0x400
#using <mscorlib.dll>
#include <windows.h>
#include <mscoree.h>
#include <iostream>
using namespace std;
#if defined(Yield)
#undef Yield
#endif
#define CORHOST
namespace Fibers {
typedef System::Runtime::InteropServices::GCHandle GCHandle;
VOID CALLBACK unmanaged_fiberproc(PVOID pvoid);
__gc private struct StopFiber {};
enum FiberStateEnum {
FiberCreated, FiberRunning, FiberStopPending, FiberStopped
};
#pragma unmanaged
#if defined(CORHOST)
ICorRuntimeHost *corhost;
void initialize_corhost() {
CorBindToCurrentRuntime(0, CLSID_CorRuntimeHost,
IID_ICorRuntimeHost, (void**) &corhost);
}
#endif
void CorSwitchToFiber(void *fiber) {
#if defined(CORHOST)
DWORD *cookie;
corhost->SwitchOutLogicalThreadState(&cookie);
#endif
SwitchToFiber(fiber);
#if defined(CORHOST)
corhost->SwitchInLogicalThreadState(cookie);
#endif
}
#pragma managed
__gc __abstract public class Fiber : public System::IDisposable {
public:
#if defined(CORHOST)
static Fiber() { initialize_corhost(); }
#endif
Fiber() : state(FiberCreated) {
void *objptr = (void*) GCHandle::op_Explicit(GCHandle::Alloc(this));
fiber = ConvertThreadToFiber(objptr);
mainfiber = fiber;
//System::Console::WriteLine(S"Created main fiber.");
}
Fiber(Fiber *_mainfiber) : state(FiberCreated) {
void *objptr = (void*) GCHandle::op_Explicit(GCHandle::Alloc(this));
fiber = CreateFiber(0, unmanaged_fiberproc, objptr);
mainfiber = _mainfiber->fiber;
//System::Console::WriteLine(S"Created worker fiber");
}
__property bool get_IsRunning() {
return state != FiberStopped;
}
int GetHashCode() {
return (int) fiber;
}
bool Resume() {
if(!fiber || state == FiberStopped) {
return false;
}
if(state == FiberStopPending) {
Dispose();
return false;
}
void *current = GetCurrentFiber();
if(fiber == current) {
return false;
}
CorSwitchToFiber(fiber);
return true;
}
void Dispose() {
if(fiber) {
void *current = GetCurrentFiber();
if(fiber == current) {
state = FiberStopPending;
CorSwitchToFiber(mainfiber);
}
state = FiberStopped;
System::Console::WriteLine(S"\nDeleting Fiber.");
DeleteFiber(fiber);
fiber = 0;
}
}
protected:
virtual void Run() = 0;
void Yield() {
CorSwitchToFiber(mainfiber);
if(state == FiberStopPending)
throw new StopFiber;
}
private:
void *fiber, *mainfiber;
FiberStateEnum state;
private public:
void main() {
state = FiberRunning;
try {
Run();
} catch(System::Object *x) {
System::Console::Error->WriteLine(
S"\nFIBERS.DLL: main Caught {0}", x);
}
Dispose();
}
};
void fibermain(void* objptr) {
//System::Console::WriteLine( S"\nfibermain()");
System::IntPtr ptr = (System::IntPtr) objptr;
GCHandle g = GCHandle::op_Explicit(ptr);
Fiber *fiber = static_cast<Fiber*>(g.Target);
g.Free();
fiber->main();
System::Console::WriteLine(S"\nfibermain returning");
}
#pragma unmanaged
VOID CALLBACK unmanaged_fiberproc(PVOID objptr) {
#if defined(CORHOST)
corhost->CreateLogicalThreadState();
#endif
fibermain(objptr);
#if defined(CORHOST)
corhost->DeleteLogicalThreadState();
#endif
}
}
उपरोक्त fibers.cpp क्लास फ़ाइल Visaul C++ प्रोजेक्ट में एकमात्र कक्षा है। इसे सीएलआर समर्थन के साथ डीएलएल के रूप में बनाया गया है/सीएलआर: पुराना स्टाइल स्विच।
using System;
using System.Threading;
using Fibers;
using NUnit.Framework;
namespace TickZoom.Utilities
{
public class FiberTask : Fiber
{
public FiberTask()
{
}
public FiberTask(FiberTask mainTask)
: base(mainTask)
{
}
protected override void Run()
{
while (true)
{
Console.WriteLine("Top of worker loop.");
try
{
Work();
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
Console.WriteLine("After the exception.");
Work();
}
}
private void Work()
{
Console.WriteLine("Doing work on fiber: " + GetHashCode() + ", thread id: " + Thread.CurrentThread.ManagedThreadId);
++counter;
Console.WriteLine("Incremented counter " + counter);
if (counter == 2)
{
Console.WriteLine("Throwing an exception.");
throw new InvalidCastException("Just a test exception.");
}
Yield();
}
public static int counter;
}
[TestFixture]
public class TestingFibers
{
[Test]
public void TestIdeas()
{
var fiberTasks = new System.Collections.Generic.List<FiberTask>();
var mainFiber = new FiberTask();
for(var i=0; i< 5; i++)
{
fiberTasks.Add(new FiberTask(mainFiber));
}
for (var i = 0; i < fiberTasks.Count; i++)
{
Console.WriteLine("Resuming " + i);
var fiberTask = fiberTasks[i];
if(!fiberTask.Resume())
{
Console.WriteLine("Fiber " + i + " was disposed.");
fiberTasks.RemoveAt(i);
i--;
}
}
for (var i = 0; i < fiberTasks.Count; i++)
{
Console.WriteLine("Disposing " + i);
fiberTasks[i].Dispose();
}
}
}
}
ऊपर इकाई परीक्षण निम्न उत्पादन देता है और फिर बुरी तरह से दुर्घटनाओं:
Resuming 0
Top of worker loop.
Doing work on fiber: 476184704, thread id: 7
Incremented counter 1
Resuming 1
Top of worker loop.
Doing work on fiber: 453842656, thread id: 7
Incremented counter 2
Throwing an exception.
Exception: Just a test exception.
After the exception.
और आप क्या सी #/एफएक्स संस्करण का उपयोग कर रहे हैं? मूल को Fx2 –
के लिए पहले से ही फ्लैकी माना जाता था यह सी # 3.5 है। तो क्या यह निराशाजनक है? हम उच्च प्रदर्शन शेड्यूलिंग के लिए थ्रेड स्टेट को स्टोर और फिर से शुरू करने के तरीके को समझने के लिए बेताब हैं। मुझे यह अन्य प्रश्न मिला है जो अधिक सामान्य है और हमें इस क्षमता की आवश्यकता क्यों है, इसकी पृष्ठभूमि बताती है। समाधान के लिए कोई अन्य विचार सबसे स्वागत है! http://stackoverflow.com/questions/8685806/c-sharp-first-class-continuation-via-c-interop-or-some-other-way – Wayne
विकल्पों के साथ एक संबंधित SO धागा: [क्या कोई फाइबर एपीआई है .NET?] (http://stackoverflow.com/questions/1949051/is-there-a-fiber-api-in-net) –