C# 交叉关注的循环依赖

C# 交叉关注的循环依赖,c#,multithreading,circular-dependency,C#,Multithreading,Circular Dependency,所以,这个例子是为了给我试图修改的更大的系统(即Orchard CMS)提供一个简单的视图。因此,它可能并不完美 我正在尝试创建一个通过设置管理的日志系统。我遇到的问题是,检索设置会导致发生日志记录。下面是一个简单的示例,希望能够描述这个问题: static void Main(string[] args) { string[] messages = "this is a test. but it's going to be an issue!".Split(' '); P

所以,这个例子是为了给我试图修改的更大的系统(即Orchard CMS)提供一个简单的视图。因此,它可能并不完美


我正在尝试创建一个通过设置管理的日志系统。我遇到的问题是,检索设置会导致发生日志记录。下面是一个简单的示例,希望能够描述这个问题:

static void Main(string[] args)
{
    string[] messages = "this is a test.  but it's going to be an issue!".Split(' ');

    Parallel.ForEach(messages, Log);

    Console.ReadLine();
}

public static void Log(string message)
{
    Console.WriteLine(GetPrefix() + message);
}

public static string GetPrefix()
{
    Log("Getting prefix!");
    return "Prefix: ";
}
这是一个明显的
StackOverflowException
。但是,我如何解决它?在从
GetPrefix
获得响应之前,我不能禁用日志记录,因为我可能会错过日志。(事实上,在这个简单的例子中,除了第一个,我错过了所有。)

(^Bad)

请注意,我目前无法控制
GetPrefix
方法,只能控制
Log
方法


我不确定是否有办法解决这个问题;我可能需要将设置放在其他位置(例如配置或单独的设置文件)。但是,如果有人有想法或建议,我很乐意尝试任何东西,因为我更愿意保留现在的设置(在管理界面中)。

将日志方法拆分为:

public static void LogWithPrefix(string message)
{
    var prefix = GetPrefix();
    Log(prefix + message);
}

public static void Log(string message)
{
    Console.WriteLine(message);
}

您只需在当前堆栈帧上禁用。现在,您可以使用反射遍历堆栈帧,看看是否调用了它,但是有一个更简单的方法。每个线程都有一个堆栈框架。因此,使静态变量
[ThreadStatic]

[线程静态] 静态bool _disable=false

这是怎么回事

“指示静态字段的值对于每个线程都是唯一的。”

编辑:然而,光是这一点可能还不够。您可能希望每个任务有一个静态变量。现在,由于任务将按线程顺序执行,在这种特殊情况下,我不认为这是一个问题,除非记录器可能在不禁用的情况下失败。。。我不确定在这种情况下会发生什么,但可能需要您至少在try/finally块中封装一些内容:

static void Main() //Main(string[] args)
{
    string[] messages = "this is a test.  but it's going to be an issue!".Split(' ');

    Parallel.ForEach(messages, Log);

    Console.ReadLine();
}
[ThreadStatic]
static bool _disable = false;
public static void Log(string message)
{
    if (_disable)
    {
        return;
    }
    try {
        _disable = true;
        Console.WriteLine(GetPrefix() + message);
    } finally {
        _disable = false;
    }
}

public static string GetPrefix()
{
    Log("Getting prefix!");
    return "Prefix: ";
}

编辑II:看起来,一旦一组任务中的任何一个在任务委托之外抛出异常,就不能保证执行任何剩余的任务。最好在您的代表中处理这些特殊情况。

前缀是必需的。在这种情况下,获取前缀表示获取日志记录设置。没有这些,我不知道记录什么或在哪里。@zimdanen:那么,
log(“获取前缀”)在哪里
在您的原始示例中应该登录到?@JayC:我想禁用它,这样它就不会在任何地方登录。您必须同步访问
bool\u disable
。您失去了并行执行,这在本例中很好,因为
Console.WriteLine
仍然是同步的。@Ginosaji:这是一个简单的示例,但在实际示例中,同步将对性能产生严重影响。您仍然可以并行处理消息,只需同步日志记录即可。正如我所说,
Console.WriteLine
无论如何都是同步的,因此通过锁定
bool\u disable
@Ginosaji:
Console,您不会丢失任何东西。WriteLine
并没有在真正的解决方案中使用。假设我们不能连续地记录日志-它需要能够一次处理多个日志。+1:这在人为的示例中非常有效。看起来也有。我会玩这个游戏,看看它的表现如何,然后带着反馈回来。谢谢
static void Main() //Main(string[] args)
{
    string[] messages = "this is a test.  but it's going to be an issue!".Split(' ');

    Parallel.ForEach(messages, Log);

    Console.ReadLine();
}
[ThreadStatic]
static bool _disable = false;
public static void Log(string message)
{
    if (_disable)
    {
        return;
    }
    try {
        _disable = true;
        Console.WriteLine(GetPrefix() + message);
    } finally {
        _disable = false;
    }
}

public static string GetPrefix()
{
    Log("Getting prefix!");
    return "Prefix: ";
}