Хорошо, следующая ссылка содержит предупреждение о том, что в обсуждении используются неподдерживаемые и недокументированные apis. Ну, я пытаюсь использовать пример кода любым способом. Это в основном работает. Какие-либо идеи по конкретному вопросу ниже, касающемуся исключений?
http://msdn.microsoft.com/en-us/magazine/cc164086.aspx
К вашему сведению, я сделал улучшение по сравнению с оригинальным образцом. Он поддерживал указатель на «предыдущее волокно». Вместо этого в обновленном примере ниже используется указатель «mainfiber», который передается каждому классу волокон. Таким образом, они всегда возвращаются к основному волокну. Это позволяет основному волокну обрабатывать планирование для всех других волокон. Другие волокна всегда «возвращаются» к основному волокну.
Причина публикации этого вопроса связана с выдачей исключений внутри волокна. Согласно статье, используя API-интерфейс CorBindToRunTime с CreateLogicalThreadState (), SwitchOutLogicalThreadState () и т. Д., Инфраструктура будет создавать управляемый поток для каждого волокна и правильно обрабатывать исключения.
Однако во включенных примерах кода имеется тест UUnit, который экспериментирует с генерацией управляемого исключения в волокне, а также с его перехватом в том же волокне. Это мягкое из работ. Но после обработки этого сообщения в журнале кажется, что стек находится в плохом состоянии, потому что, если волокно вызывает какой-либо другой метод, даже пустой метод, целое приложение вылетает.
Это подразумевает, что SwitchOutLogicalThreadState () и SwitchInLogicalThreadState (), возможно, не используются должным образом, или, может быть, они не выполняют свою работу.
ПРИМЕЧАНИЕ. Одним из объяснений этой проблемы является то, что управляемый код регистрирует Thread.CurrentThread.ManagedThreadId, и он одинаков для каждого волокна. Это говорит о том, что метод CreateLogicalThreadState () на самом деле не создал новый управляемый поток, как объявлено.
Чтобы лучше это проанализировать, я составил список псевдокодов порядка низкоуровневых API, вызываемых для обработки волокон. Помните, что все волокна работают в одном потоке, поэтому одновременно ничего не происходит, это линейная логика. Конечно, необходимая хитрость - сохранить и восстановить стек. Вот где, похоже, возникают проблемы.
Он начинается как простой поток, а затем преобразуется в волокно:
- ConvertThreadToFiber (ObjPtr);
- CreateFiber () // создать несколько волокон win32.
Теперь вызовите волокно в первый раз, метод запуска делает это:
- corhost-> SwitchOutLogicalThreadState (& печенье); Основной файл cookie
удерживается в стеке.
- SwitchToFiber (); // первый раз вызывает метод запуска волокна
- corhost-> CreateLogicalThreadState ();
- запустить метод абстрактного основного волокна.
В конечном итоге волокно должно возвращаться к основному волокну:
- corhost-> SwitchOutLogicalThreadState (& печенье);
- corhost-> SwitchInLogicalThreadState (& печенье); // основное волокно
печенье, верно?
Также основное волокно возобновит работу ранее существовавшего волокна:
- corhost-> SwitchOutLogicalThreadState (& печенья);
- SwitchToFiber (волокно); * * тысяча пятьдесят-три
- corhost-> SwitchInLogicalThreadState (& печенье); // основное волокно cookie, верно?
Ниже приведен файл fiber.cpp, который упаковывает API-интерфейс fiber для управляемого кода.
#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
}
}
Приведенный выше файл fiber.cpp является единственным классом в проекте Visaul c ++. Он построен как DLL с поддержкой CLR с использованием ключа / CLR: oldstyle.
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.