gpt4 book ai didi

c# - 在 CLR 中使用托管线程和纤程

转载 作者:IT老高 更新时间:2023-10-28 22:22:32 27 4
gpt4 key购买 nike

好的,下面的链接有一个警告,说明讨论使用了不受支持和未记录的 api。好吧,我正在尝试以任何方式使用代码示例。它主要工作。关于以下与异常(exception)相关的具体问题有什么想法吗?

http://msdn.microsoft.com/en-us/magazine/cc164086.aspx

仅供引用,我对原始样本进行了改进。它正在维护一个指向“previousfiber”的指针。相反,下面的更新示例使用了一个“mainfiber”指针,该指针被传递给每个光纤类。这样,它们总是屈服于主纤维。这允许主纤程处理所有其他纤程的调度。其他纤维总是“屈服”回主要纤维。

发布此问题的原因与在光纤中抛出异常有关。根据文章,通过使用 CorBindToRunTime API 和 CreateLogicalThreadState()、SwitchOutLogicalThreadState() 等,框架将为每个纤程创建一个托管线程并正确处理异常。

但是,在包含的代码示例中,它有一个 UUnit 测试,该测试尝试在 Fiber 中抛出托管异常并在同一 Fiber 中捕获它。那种柔软的作品。但是在通过记录消息处理它之后,堆栈似乎处于错误状态,因为如果纤程调用任何其他方法甚至是空方法,整个应用程序都会崩溃。

这对我来说意味着 SwitchOutLogicalThreadState() 和 SwitchInLogicalThreadState() 可能没有被正确使用,或者他们可能没有做他们的工作。

注意:问题的一个线索是托管代码注销了 Thread.CurrentThread.ManagedThreadId 并且对于每条光纤都是相同的。这表明 CreateLogicalThreadState() 方法并没有像宣传的那样真正创建新的托管线程。

为了更好地分析这一点,我制作了一个伪代码列表,列出了调用来处理纤程的低级 API 的顺序。请记住,纤程都在同一个线程上运行,因此不会同时发生任何事情,这是一个线性逻辑。必要的技巧当然是保存和恢复堆栈。这就是它似乎遇到问题的地方。

它一开始只是一个线程,然后它转换为纤维:

  1. ConvertThreadToFiber(objptr);
  2. CreateFiber()//创建多个 win32 光纤。

现在第一次调用一个纤程,它的启动方法是这样的:

  1. corhost->SwitchOutLogicalThreadState(&cookie);主要的cookie是保留在堆栈上。
  2. SwitchToFiber();//第一次调用光纤启动方法
  3. corhost->CreateLogicalThreadState();
  4. 运行主要的 Fiber 抽象方法。

最终纤维需要屈服于主纤维:

  1. corhost->SwitchOutLogicalThreadState(&cookie);
  2. SwitchToFiber(光纤);
  3. corhost->SwitchInLogicalThreadState(&cookie);//主光纤 cookies ,对吧?

主纤也将恢复先前存在的纤:

  1. corhost->SwitchOutLogicalThreadState(&cookie);
  2. SwitchToFiber(光纤);
  3. corhost->SwitchInLogicalThreadState(&cookie);//主要的纤维 cookies ,对吧?

以下是为托管代码包装了 Fiber api 的 fiber.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++项目中唯一的类。它使用/CLR:oldstyle 开关构建为具有 CLR 支持的 DLL。

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.

最佳答案

前段时间,我遇到了同样的问题 - 我尝试在 .NET 3.5(后来的 4.0)中使用代码片段,但它崩溃了。这说服了我放弃“hacky”解决方案。事实上,.NET 缺少一个通用的协同程序概念。有些人通过枚举器和 yield 关键字模拟协同程序(参见 http://fxcritic.blogspot.com/2008/05/lightweight-fibercoroutines.html )。然而,这对我来说有明显的缺点:它不像旧的 Win32 纤程那样直观,它需要您使用 IEnumerable 作为每个协程的返回类型。

也许这篇文章:http://msdn.microsoft.com/en-us/vstudio/gg316360对你来说很有趣。微软即将引入一个新的 async 关键字。提供社区技术预览 (CTP) 供下载。我想应该可以在这些异步扩展之上开发一个干净的协程实现。

关于c# - 在 CLR 中使用托管线程和纤程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8688400/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com