说了创建异步方法,再来看看使用C++调用WinRT的异步方法。由于C++中没有async/await那样的异步模式,所以最值得关心的就是如何,所以当一个任务完成后需要手动传入剩余的代码来继续后续任务的执行,这里需要用到task的then方法,首先我们需要把IAsyncInfo转为task。(其实上面的代码已经演示了这个用法)
不同于C#中通过AsTask方法将IAsyncInfo等类型转为Task对象。C++中是使用create_task的方法(就是上面介绍的那个,不同的重载)来完成这个工作:
auto createFileTadk =create_task(folder->CreateFileAsync("aa.txt",CreationCollisionOption::ReplaceExisting));接着调用task的then方法设置后续执行:
createFileTadk.then([this](StorageFile^ storageFileSample) { String^ filename=storageFileSample->Name; });
捕获异常方面,不涉及WinRT的部分遵循C++的异常捕获原则,WinRT交互部分,需要保证抛出的异常可以被WinRT识别处理。
除了使用ppltask.h中的扩展,还可以使用WRL中的AsyncBase模板类来实现C++对WiinRT异步的支持。但后者的代码过于晦涩,就不再介绍了。
说回来和WinRT交互就好用的语言还是C#,C++可以用于实现纯算法部分,即位于WinRT下方的部分,只需要在必要的时候通过WinRT公开让C#可调用的接口。这样代码的编写效率和执行效率都很高。另外C#的应用商店程序支持本地编译也是大势所趋,在WinRT之上使用C#或C++/CX区别不大。
C++ 11 线程&并发&异步
C++在沉寂多年之后,终于在新版标准中迎来爆发,其中标准内置的线程支持就是一个完全全新的特性。在之前版本的C++中没有标准的线程库,实现跨平台的线程操作一般都要借助于第三方的库。现在有了C++11,相同的操作线程的代码可以在不同的编译器上编译执行从而可以实现跨平台的线程操作。
C++新标准中的线程,异步等看起来和C#的机制非常的像,不知道微软和C++标准委员会谁“借鉴”的谁。
下面按线程,并发中同步支持,异步这样的顺序来逐个了解下C++新标准中增加的这些特性。介绍方式以C#的等价机制做对比,篇幅原因很多都是一个纲领作用,介绍一笔带过,根据需要大家自行查找相应的功能的具体使用方法。
线程
C++11标准库中引入了std::thread作为抽象线程的类型。其很多操作和.NET中的Thread类似。
C++ 11 C#
std::thread Thread
创建 constructor constructor
插入一个线程 t.join() t表示std::thread对象,下同 t.Join() t表示Thread对象,下同
分离线程 t.detach() 无
获取线程id t.get_id() Thread.CurrentThread.ManagedThreadId
线程休眠 std::this_thread::sleep_for() Thread.Sleep()
一段简单的综合示例代码:
int main() { std::thread t1([](int a){ std::this_thread::sleep_for(std::chrono::seconds(2)) }, 3); t1.join(); t1.detach(); return 0; }
多线程 - 互斥
C++11中内建了互斥机制,可以让多个线程安全的访问同一个变量。几种机制总结如下(可能并非完全一直,但效果上很类似)
C++ 11 C#
原子类型
atomic_type
std::atomic<T>
Interlocked内存栅栏 memory_order_type MemoryBarrier
线程本地存储 thread_local
ThreadStatic
LocalDataStoreSlot
ThreadLocal<T>
互斥
std::mutex
std::timed_mutex
std::recursive_mutex
std::recursive_timed_mutex
Mutex锁 lock_guard<T> lock
通知
condition_variable
condition_variable_any
(notify_one/notify_all)
ManualResetEvent
AutoResetEvent
初始化 call_once
上面介绍的线程或多线程支持都是一些很底层的接口。针对异步操作C++11还提供了一些高级接口,其中具有代表性的对象就是std::future和std::async。
std::future和C#中的TaskAwaiter比较相似,而std::async作用正如C#中使用async关键字标记的异步方法。在C++11中通过std::async将一个可调用对象包装厂一个异步方法,这个方法将返回一个std::future对象,通过std::future可以得到异步方法的结果。
看一下这段代码(来自qicosmos老师的博文)就能明白上面所说:
std::future<int> f1 = std::async(std::launch::async, [](){ return 8; }); cout<<f1.get()<<endl;关于C++11异步方面的特性,强烈推荐qicosmos老师的博文以及他编写的图书《深入应用C++11:代码优化与工程级应用》。
C# 方法调用方信息
新版本的C#提供了方便获取方法调用者信息的功能,对于需要调试以及输出一些日志的情况很有用。这样我们不需要像之前那样在每个需要记录日志的地方硬编码下调用的方法名,提高了代码的可读性。
提供这个新功能的是几个应用于参数的Attribute:
CallerFilePathAttribute 获得调用方法所在的源文件地址
CallerLineNumberAttribute 被调用代码的行号
CallerMemberNameAttribute 调用方法的名称