В целом исключения включали, необходимо рассматривать дополнительный метод, как будто это был нормальный статический метод. В этом случае необходимо бросить ArgumentNullException.
Бросок NullReferenceException вот является плохой идеей по нескольким причинам
Видят , Когда может Вы ловить StackOverflowException (сообщение, я сделал на этом предмете).
к сожалению, нет простого пути. Пара вариантов: pthread в Linux, потоки Win32 API в Windows или библиотека boost :: thread
Это полностью зависит от того, что вы делаете. Если вы можете вписать то, что делаете, в OpenMP, тогда это правильный путь. В противном случае вы можете посмотреть Intel TBB . TBB предлагает несколько рабочих процессов, в которые вы должны уметь вписаться, но библиотека имеет двойную лицензию, и вы не сможете принять любую из этих лицензий. Если отсутствуют и OpenMP, и TBB, то вам следует рассмотреть возможности пулов потоков вашей операционной системы.
В какой-то момент вам может потребоваться укусить пулю и использовать Boost.Thread. Если это так, вы захотите посмотреть , что делает многопоточность в C ++ сложной. (полезно читать, даже если вы не используете C ++ 0x: «Это не сами потоки, а взаимодействие, которое вызывает Проблемы. Изменяемое разделяемое состояние вводит неявную связь », стр. 3).
Posix Thread неплохо, они также поставляются с отличной документацией и руководствами.
Не так просто, как потоки Java, но все же неплохо.
Я бы сказал с Qt . Qt Threads и Qt Concurrency, вероятно, стоит поискать в Google.
It's been a while since I worked in C++ and I haven't seen the Boost threading support, but I found it very helpful to encapsulate semaphore services provided by the OS, usually either POSIX or Win32, in simple classes that would acquire locks, and release them in the destructors, making their use fairly simple.
void operateOnSharedResource(SharableResource & foo) {
MutexLock lock(foo.getMutex());
// do stuff to foo
// implicit call to MutexLock dtor performs release
}
Ultimately there are lots of simple tricks like this to ease thread programming and I'd be surprised if Boost didn't have something like this by now (EDIT: It does and it's documented in Lock Types).
Regardless, the main problem with writing multi-threaded code isn't going to be solved by any third party library, and that's understanding where your code can be parallelized usefully, and where shared resources are going to be touched and must be accounted for. Here's a few rules of thumb I use when writing multi-threaded code.
Proper encapsulation really does wonders for writing safer multi-threaded code, because the fewer things you can see, the fewer things can have a race condition.
Boost.Thread относительно проще, потому что он переносим, хорошо документирован и имеет высокоуровневый API, такой как scoped_try_lock .
The C++0x specification includes threading facilities (one of my favorite new features). Soon it won't matter what OS you're compiling for! Just look how easy it is to create a new thread and join back to the creator thread:
#include <thread>
#include <iostream>
class SayHello
{
public:
void operator()() const
{
std::cout<<"hello"<<std::endl;
}
};
int main()
{
std::thread t((SayHello()));
t.join();
}
Visual Studio 2010 is implementing parts of C++0x but we're still waiting on the threading facilities.
There is no simple answer to this. It depends very heavily on what you hope to gain from multithreading, the platform/compiler, and which threading model you want to use. Every threading API has its pitfalls.
And just because no one has mentioned it so far, OpenMP is another option that is supported in many modern mainstream compilers and is intended to simplify the use of concurrency. http://openmp.org/wp/
Qt имеет довольно поддержка потоковой передачи и документация но, как предупреждали другие, это не для новичков. Ссылка на документ, которую я дал, указывает на короткий список чтения
Просто упомяну, потому что не упоминалось: компилятор с поддержкой OpenMP ( http://openmp.org/wp/ )
Нет нет easy способ создания многопоточного приложения на любом языке.
I'm not sure about the easiest, but IMO the most user-friendly threading library is the one included in the Poco C++ project. For a preview have a look at the Thread.h header file.
Обновление: похоже, Technitium нашел другой способ сделать это, который выглядит намного проще, по крайней мере, в новых версиях ASP.NET MVC. (скопировал его комментарий ниже)
Я не уверен, что это новое в ASP.NET MVC 3, но когда я поменял местами Наследует атрибут от ссылки на универсальный синтаксис C # на CLR синтаксис, стандартный
ViewPageParserFilter
правильно проанализировал универсальные шаблоны - не требуетсяCustomViewTypeParserFilter
. Используя примеры Джастина, это означает замену
<%@ Page Language="C#" MyNewProperty="From @Page directive!"
Inherits="JG.ParserFilter.CustomViewPage<MvcApplication1.Models.FooModel>
на
<%@ Page Language="C#" MyNewProperty="From @Page directive!"`
Inherits="JG.ParserFilter.CustomViewPage`1[MvcApplication1.Models.FooModel]>
Исходный ответ ниже:
Хорошо, я решил это. Это было увлекательное упражнение, и решение нетривиальное, но не слишком сложное, если оно сработает с первого раза.
Вот основная проблема: синтаксический анализатор страницы ASP.NET не поддерживает универсальные шаблоны как тип страницы.
ASP.NET MVC работал с этой проблемой, обманывая базовый синтаксический анализатор страницы, заставляя его думать, что страница не является универсальной. . Они сделали это путем создания пользовательского PageParserFilter и пользовательского FileLevelPageControlBuilder . Фильтр синтаксического анализатора ищет общий тип и, если он его находит, заменяет его на неуниверсальный тип ViewPage, чтобы синтаксический анализатор ASP.NET не подавился. Затем, намного позже в жизненном цикле компиляции страницы, их класс настраиваемого конструктора страниц снова меняет общий тип.
Это работает, потому что общий тип ViewPage является производным от неуниверсального ViewPage, и все интересные свойства, которые задаются в директиве @Page, существуют в (неуниверсальном) базовом классе. Итак, что на самом деле происходит, когда свойства устанавливаются в директиве @Page, заключается в том, что эти имена свойств проверяются на предмет неуниверсального базового класса ViewPage.
В любом случае, в большинстве случаев это отлично работает, но не в вашем, потому что они жестко запрограммировали ViewPage как неуниверсальный базовый тип в своей реализации фильтра страниц и не предоставляют простого способа его изменить. Вот почему вы продолжали видеть ViewPage в своем сообщении об ошибке, поскольку ошибка возникает между тем, когда ASP.NET меняет местозаполнитель ViewPage, и когда он меняет обратно общий ViewPage прямо перед компиляцией.
Исправление заключается в создании вашей собственной версии. из следующих:
Затем вам нужно изменить веб. config в каталоге представлений (а не в файле web.config основного приложения), чтобы использовать эти новые типы вместо типов MVC по умолчанию.
Я приложил несколько примеров кода, иллюстрирующих, как это работает. Большое спасибо статье Фила Хаака, которая помогла мне понять это, хотя мне пришлось много копаться в исходном коде MVC и ASP.NET, чтобы по-настоящему понять это.
Сначала я начну с web.config изменения, необходимые в вашем web.config:
<pages
validateRequest="false"
pageParserFilterType="JG.ParserFilter.CustomViewTypeParserFilter"
pageBaseType="JG.ParserFilter.CustomViewPage"
userControlBaseType="JG.ParserFilter.CustomViewUserControl">
Теперь вот фильтр парсера страницы (# 1 выше):
namespace JG.ParserFilter {
using System;
using System.Collections;
using System.Web.UI;
using System.Web.Mvc;
internal class CustomViewTypeParserFilter : PageParserFilter
{
private string _viewBaseType;
private DirectiveType _directiveType = DirectiveType.Unknown;
private bool _viewTypeControlAdded;
public override void PreprocessDirective(string directiveName, IDictionary attributes) {
base.PreprocessDirective(directiveName, attributes);
string defaultBaseType = null;
// If we recognize the directive, keep track of what it was. If we don't recognize
// the directive then just stop.
switch (directiveName) {
case "page":
_directiveType = DirectiveType.Page;
defaultBaseType = typeof(JG.ParserFilter.CustomViewPage).FullName; // JG: inject custom types here
break;
case "control":
_directiveType = DirectiveType.UserControl;
defaultBaseType = typeof(JG.ParserFilter.CustomViewUserControl).FullName; // JG: inject custom types here
break;
case "master":
_directiveType = DirectiveType.Master;
defaultBaseType = typeof(System.Web.Mvc.ViewMasterPage).FullName;
break;
}
if (_directiveType == DirectiveType.Unknown) {
// If we're processing an unknown directive (e.g. a register directive), stop processing
return;
}
// Look for an inherit attribute
string inherits = (string)attributes["inherits"];
if (!String.IsNullOrEmpty(inherits)) {
// If it doesn't look like a generic type, don't do anything special,
// and let the parser do its normal processing
if (IsGenericTypeString(inherits)) {
// Remove the inherits attribute so the parser doesn't blow up
attributes["inherits"] = defaultBaseType;
// Remember the full type string so we can later give it to the ControlBuilder
_viewBaseType = inherits;
}
}
}
private static bool IsGenericTypeString(string typeName) {
// Detect C# and VB generic syntax
// REVIEW: what about other languages?
return typeName.IndexOfAny(new char[] { '<', '(' }) >= 0;
}
public override void ParseComplete(ControlBuilder rootBuilder) {
base.ParseComplete(rootBuilder);
// If it's our page ControlBuilder, give it the base type string
CustomViewPageControlBuilder pageBuilder = rootBuilder as JG.ParserFilter.CustomViewPageControlBuilder; // JG: inject custom types here
if (pageBuilder != null) {
pageBuilder.PageBaseType = _viewBaseType;
}
CustomViewUserControlControlBuilder userControlBuilder = rootBuilder as JG.ParserFilter.CustomViewUserControlControlBuilder; // JG: inject custom types here
if (userControlBuilder != null) {
userControlBuilder.UserControlBaseType = _viewBaseType;
}
}
public override bool ProcessCodeConstruct(CodeConstructType codeType, string code) {
if (codeType == CodeConstructType.ExpressionSnippet &&
!_viewTypeControlAdded &&
_viewBaseType != null &&
_directiveType == DirectiveType.Master) {
// If we're dealing with a master page that needs to have its base type set, do it here.
// It's done by adding the ViewType control, which has a builder that sets the base type.
// The code currently assumes that the file in question contains a code snippet, since
// that's the item we key off of in order to know when to add the ViewType control.
Hashtable attribs = new Hashtable();
attribs["typename"] = _viewBaseType;
AddControl(typeof(System.Web.Mvc.ViewType), attribs);
_viewTypeControlAdded = true;
}
return base.ProcessCodeConstruct(codeType, code);
}
// Everything else in this class is unrelated to our 'inherits' handling.
// Since PageParserFilter blocks everything by default, we need to unblock it
public override bool AllowCode {
get {
return true;
}
}
public override bool AllowBaseType(Type baseType) {
return true;
}
public override bool AllowControl(Type controlType, ControlBuilder builder) {
return true;
}
public override bool AllowVirtualReference(string referenceVirtualPath, VirtualReferenceType referenceType) {
return true;
}
public override bool AllowServerSideInclude(string includeVirtualPath) {
return true;
}
public override int NumberOfControlsAllowed {
get {
return -1;
}
}
public override int NumberOfDirectDependenciesAllowed {
get {
return -1;
}
}
public override int TotalNumberOfDependenciesAllowed {
get {
return -1;
}
}
private enum DirectiveType {
Unknown,
Page,
UserControl,
Master,
}
}
}
Вот класс компоновщика страниц (# 2 выше):
namespace JG.ParserFilter {
using System.CodeDom;
using System.Web.UI;
internal sealed class CustomViewPageControlBuilder : FileLevelPageControlBuilder {
public string PageBaseType {
get;
set;
}
public override void ProcessGeneratedCode(
CodeCompileUnit codeCompileUnit,
CodeTypeDeclaration baseType,
CodeTypeDeclaration derivedType,
CodeMemberMethod buildMethod,
CodeMemberMethod dataBindingMethod) {
// If we find got a base class string, use it
if (PageBaseType != null) {
derivedType.BaseTypes[0] = new CodeTypeReference(PageBaseType);
}
}
}
}
А вот классы настраиваемых страниц просмотра: неуниверсальный базовый (№3 выше) и общий производный класс (№4 выше):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Diagnostics.CodeAnalysis;
using System.Web.Mvc;
namespace JG.ParserFilter
{
[FileLevelControlBuilder(typeof(JG.ParserFilter.CustomViewPageControlBuilder))]
public class CustomViewPage : System.Web.Mvc.ViewPage //, IAttributeAccessor
{
public string MyNewProperty { get; set; }
}
[FileLevelControlBuilder(typeof(JG.ParserFilter.CustomViewPageControlBuilder))]
public class CustomViewPage<TModel> : CustomViewPage
where TModel : class
{
// code copied from source of ViewPage<T>
private ViewDataDictionary<TModel> _viewData;
public new AjaxHelper<TModel> Ajax
{
get;
set;
}
public new HtmlHelper<TModel> Html
{
get;
set;
}
public new TModel Model
{
get
{
return ViewData.Model;
}
}
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public new ViewDataDictionary<TModel> ViewData
{
get
{
if (_viewData == null)
{
SetViewData(new ViewDataDictionary<TModel>());
}
return _viewData;
}
set
{
SetViewData(value);
}
}
public override void InitHelpers()
{
base.InitHelpers();
Ajax = new AjaxHelper<TModel>(ViewContext, this);
Html = new HtmlHelper<TModel>(ViewContext, this);
}
protected override void SetViewData(ViewDataDictionary viewData)
{
_viewData = new ViewDataDictionary<TModel>(viewData);
base.SetViewData(_viewData);
}
}
}
И вот соответствующие классы для пользовательских элементов управления (№5 выше):
namespace JG.ParserFilter
{
using System.Diagnostics.CodeAnalysis;
using System.Web.Mvc;
using System.Web.UI;
[FileLevelControlBuilder(typeof(JG.ParserFilter.CustomViewUserControlControlBuilder))]
public class CustomViewUserControl : System.Web.Mvc.ViewUserControl
{
public string MyNewProperty { get; set; }
}
public class CustomViewUserControl<TModel> : CustomViewUserControl where TModel : class
{
private AjaxHelper<TModel> _ajaxHelper;
private HtmlHelper<TModel> _htmlHelper;
private ViewDataDictionary<TModel> _viewData;
public new AjaxHelper<TModel> Ajax {
get {
if (_ajaxHelper == null) {
_ajaxHelper = new AjaxHelper<TModel>(ViewContext, this);
}
return _ajaxHelper;
}
}
public new HtmlHelper<TModel> Html {
get {
if (_htmlHelper == null) {
_htmlHelper = new HtmlHelper<TModel>(ViewContext, this);
}
return _htmlHelper;
}
}
public new TModel Model {
get {
return ViewData.Model;
}
}
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public new ViewDataDictionary<TModel> ViewData {
get {
EnsureViewData();
return _viewData;
}
set {
SetViewData(value);
}
}
protected override void SetViewData(ViewDataDictionary viewData) {
_viewData = new ViewDataDictionary<TModel>(viewData);
base.SetViewData(_viewData);
}
}
}
namespace JG.ParserFilter {
using System.CodeDom;
using System.Web.UI;
internal sealed class CustomViewUserControlControlBuilder : FileLevelUserControlBuilder {
internal string UserControlBaseType {
get;
set;
}
public override void ProcessGeneratedCode(
CodeCompileUnit codeCompileUnit,
CodeTypeDeclaration baseType,
CodeTypeDeclaration derivedType,
CodeMemberMethod buildMethod,
CodeMemberMethod dataBindingMethod) {
// If we find got a base class string, use it
if (UserControlBaseType != null) {
derivedType.BaseTypes[0] = new CodeTypeReference(UserControlBaseType);
}
}
}
}
Наконец, вот образец представления, который показывает это В бою:
Помимо уже упомянутых, ACE - еще одна популярная и широко применяемая среда C ++, которая обеспечивает инкапсуляцию потоков на нескольких платформах. Его стиль C ++ не такой современный, как, например, Boost.Thread , но он довольно зрелый.