Что самый легкий путь состоит в том, чтобы создать многопоточные приложения с C/C++?

В целом исключения включали, необходимо рассматривать дополнительный метод, как будто это был нормальный статический метод. В этом случае необходимо бросить ArgumentNullException.

Бросок NullReferenceException вот является плохой идеей по нескольким причинам

  • , нулевая ссылка А на самом деле не произошла, настолько видящий - парадоксален
  • , Бросок NullReferenceException и то, чтобы заставлять NullReferenceException произойти производят заметно различные исключения (Один способ видеть, что различием является код ошибки). Это верно для многих исключений, которые выдаются CLR.

Видят , Когда может Вы ловить StackOverflowException (сообщение, я сделал на этом предмете).

  • совершенно законно назвать дополнительный метод так же, как если бы это был обычный метод. В этом случае я был бы, конечно, не кроме NullReferenceException, но вместо этого ArgumentNullException.

6
задан Peter Mortensen 20 October 2009 в 17:13
поделиться

15 ответов

к сожалению, нет простого пути. Пара вариантов: pthread в Linux, потоки Win32 API в Windows или библиотека boost :: thread

14
ответ дан 8 December 2019 в 02:00
поделиться

Это полностью зависит от того, что вы делаете. Если вы можете вписать то, что делаете, в OpenMP, тогда это правильный путь. В противном случае вы можете посмотреть Intel TBB . TBB предлагает несколько рабочих процессов, в которые вы должны уметь вписаться, но библиотека имеет двойную лицензию, и вы не сможете принять любую из этих лицензий. Если отсутствуют и OpenMP, и TBB, то вам следует рассмотреть возможности пулов потоков вашей операционной системы.

В какой-то момент вам может потребоваться укусить пулю и использовать Boost.Thread. Если это так, вы захотите посмотреть , что делает многопоточность в C ++ сложной. (полезно читать, даже если вы не используете C ++ 0x: «Это не сами потоки, а взаимодействие, которое вызывает Проблемы. Изменяемое разделяемое состояние вводит неявную связь », стр. 3).

1
ответ дан 8 December 2019 в 02:00
поделиться

Posix Thread неплохо, они также поставляются с отличной документацией и руководствами.

Не так просто, как потоки Java, но все же неплохо.

1
ответ дан 8 December 2019 в 02:00
поделиться

Я бы сказал с Qt . Qt Threads и Qt Concurrency, вероятно, стоит поискать в Google.

1
ответ дан 8 December 2019 в 02:00
поделиться

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.

  • Try to minimize the number of shared resources
  • Try to encapsulate shared resources in class wrappers that make all operations atomic.
  • Make worker threads as simple as possible

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.

3
ответ дан 8 December 2019 в 02:00
поделиться

Boost.Thread относительно проще, потому что он переносим, ​​хорошо документирован и имеет высокоуровневый API, такой как scoped_try_lock .

2
ответ дан 8 December 2019 в 02:00
поделиться

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.

2
ответ дан 8 December 2019 в 02:00
поделиться

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/

5
ответ дан 8 December 2019 в 02:00
поделиться
5
ответ дан 8 December 2019 в 02:00
поделиться

Qt имеет довольно поддержка потоковой передачи и документация но, как предупреждали другие, это не для новичков. Ссылка на документ, которую я дал, указывает на короткий список чтения

7
ответ дан 8 December 2019 в 02:00
поделиться

Просто упомяну, потому что не упоминалось: компилятор с поддержкой OpenMP ( http://openmp.org/wp/ )

8
ответ дан 8 December 2019 в 02:00
поделиться

Нет нет easy способ создания многопоточного приложения на любом языке.

14
ответ дан 8 December 2019 в 02:00
поделиться

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.

2
ответ дан 8 December 2019 в 02:00
поделиться

Обновление: похоже, 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 прямо перед компиляцией.

Исправление заключается в создании вашей собственной версии. из следующих:

  1. фильтр парсера страницы - это почти точная копия ViewTypeParserFilter.cs в исходном коде MVC, с той лишь разницей, что он относится к вашим пользовательским типам ViewPage и построителю страниц вместо построителя страниц MVC
  2. - это идентично в ViewPageControlBuilder.cs в источнике MVC, но он помещает класс в ваше собственное пространство имен, а не в их.
  3. Наследуйте свой собственный класс страницы просмотра непосредственно из System.Web.Mvc.ViewPage (неуниверсальная версия). Прикрепите любые настраиваемые свойства к этому новому неуниверсальному классу.
  4. создайте универсальный класс из №3, скопировав код из реализации ViewPage источника ASP.NET MVC.
  5. повторите № 2, № 3 и № 4 для пользовательских элементов управления (@Control), если вам также нужны настраиваемые свойства в директивах пользовательского элемента управления.

Затем вам нужно изменить веб. 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);
            }
        }
    }
}

Наконец, вот образец представления, который показывает это В бою:

1
ответ дан 8 December 2019 в 02:00
поделиться

Помимо уже упомянутых, ACE - еще одна популярная и широко применяемая среда C ++, которая обеспечивает инкапсуляцию потоков на нескольких платформах. Его стиль C ++ не такой современный, как, например, Boost.Thread , но он довольно зрелый.

2
ответ дан 8 December 2019 в 02:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: