公司的微信项目中有用到讯飞的语音识别sdk(C++编写),经过多发测试验证,发现他们的sdk不能在IIS下面运行。没办法,我们公司的强人将讯飞的sdk单独封装成一个控制台应用程序,供网站调用。其中涉及到跨进程调用,觉得很值得我学习。因此在此做下笔记。

首先记录下其中用到的一些我没怎么用过的关键字和静态类。

unsafe关键字

用到unsafe关键字需要设置项目属性-》生成-》允许不安全代码

告诉编译器这部分代码是非托管代码,涉及到指针的操作

为了保持类型安全,默认情况下,C# 不支持指针算法。 不过,通过使用 unsafe 关键字,可以定义可使用指针的不安全上下文

在公共语言运行时 (CLR) 中,不安全代码是指无法验证的代码。 C# 中的不安全代码不一定是危险的;只是其安全性无法由 CLR 进行验证的代码。 因此,CLR 只对在完全受信任的程序集中的不安全代码执行操作。 如果使用不安全代码,由您负责确保您的代码不会引起安全风险或指针错误。

不安全代码具有下列属性:

  • 方法、类型和可被定义为不安全的代码块。

  • 在某些情况下,通过移除数组界限检查,不安全代码可提高应用程序的性能。

  • 当调用需要指针的本机函数时,需要使用不安全代码。

  • 使用不安全代码将引起安全风险和稳定性风险。

  • 在 C# 中,为了编译不安全代码,必须用 /unsafe 编译应用程序。(设置项目属性-》生成-》允许不安全代码)

    http://msdn.microsoft.com/zh-cn/y31yhkeb(v=vs.80) 有详细的指针类型(C#编程指南)

(摘自MSDN)

IntPtr类

IntPtr 类型被设计成整数,其大小适用于特定平台。 即是说,此类型的实例在 32 位硬件和操作系统中将是 32 位,在 64 位硬件和操作系统上将是 64 位。

IntPtr 类型可以由支持指针的语言使用,并可作为在支持与不支持指针的语言间引用数据的一种通用方式。

IntPtr 对象也可用于保持句柄。 例如,IntPtr 的实例广泛地用在 System.IO.FileStream 类中来保持文件句柄。

IntPtr 类型符合 CLS,而 UIntPtr 类型却不符合。 只有 IntPtr 类型可用在公共语言运行时中。 UIntPtr 类型大多数是提供来维护与 IntPtr 类型之间的体系结构上的对称性。

摘自MSDN

Task类

现在C#启动一个进程写法非常的方便

 Task.Factory.StartNew<string>(() => {


                return string.Empty;
            },TaskCreationOptions.PreferFairness);


lock变量 锁住资源,防止并发中同时访问

lock (this)
{
    //执行操作
    DoSomething()....
    //比如操作静态变量,缓存等
}

防止并发操作,当前用户操作完,下个用户才能再进行操作

一般lock和一个静态型object变量进行配合

先声明一个 
private static object symObj = new object();
lock(symObj)
{
    //执行操作
    DoSomething()....
    //比如操作静态变量,缓存等
}
下面是本次的重点了,如何进行跨线程调用
(之所以这么麻烦,是因为IIS是多线程的,讯飞是多线程的,但进程间通讯是不支持多线程的)
ProcessStartInfo类 指定启动进程时使用的一组值
		var processStartInfo = new ProcessStartInfo(ProxyEXE);//ProxyEXE 进程路径
                processStartInfo.CreateNoWindow = true;
                processStartInfo.LoadUserProfile = false;
                processStartInfo.UseShellExecute = false;
                processStartInfo.RedirectStandardInput = true; //捕获命令行输出
                processStartInfo.RedirectStandardOutput = true; //捕获命令行输出
                processStartInfo.StandardOutputEncoding = Encoding.UTF8;
                ProxyProcess = Process.Start(processStartInfo);//启动进程,这时候我们需要调用的进程就已经启动了
这个控制台程序,每当控制台输入流得到一行字符串,该程序就认为这是一个amr文件路径,尝试转换到wav并提交讯飞服务器转换为文字。转换完成后,该程序会将[源文件名]+|分隔符+[识别出的文字]+换行符 写入到自己的输出流。
网站中有两个线程,其中一个线程(全局的)负责:(消费者)
 
 
  1. 在应用启动时,启动控制台程序作为子进程
  2. 不断地尝试去读取控制台程序的输出流
  3. 发现控制台程序中出现了新行,则用|分隔符分割,用[源文件名]作为键值去索引ConveryViaProxy中产生的等待者
  4. 找到了等待者,用[识别出的文字]激活它。
另一个线程负责:(生产者)
  
  
  1. 将amr文件路径写到控制台程序的输入流
  2. 以源文件名作为键值,将自己放到等待池中
  3. 等待识别结果
这里面有用到
TaskCompletionSource类在异步操作中非常有帮助
详细可以参考http://blogs.msdn.com/b/pfxteam/archive/2009/06/02/9685804.aspx

这里面用到生产者和消费者模式。

可以观看如下帖子

http://blog.csdn.net/program_think/article/details/4022087

http://zh.wikipedia.org/wiki/%E7%94%9F%E4%BA%A7%E8%80%85%E6%B6%88%E8%B4%B9%E8%80%85%E9%97%AE%E9%A2%98



Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐