草庐IT

c++ - PThread 初学者 - 启动、同步、停止工作线程

coder 2024-02-20 原文

我有以下经理<->员工情况:

class Manager {
private:
    pthread_attr_t workerSettings;
    pthread_t worker;
    pthread_cond_t condition;
    pthread_mutex_t mutex;
    bool workerRunning;

    static void* worker_function(void* args) {
        Manager* manager = (Manager*)args;

        while(true) {
            while(true) {
                pthread_mutex_lock(&manager->mutex);
                if(/* new data available */)
                {
                    /* copy new data from shared to thread memory */
                    pthread_mutex_unlock(&manager->mutex);
                }
                else
                {
                    pthread_mutex_unlock(&manager->mutex);
                    break;
                }

                /* process the data in thread memory */

                pthread_mutex_lock(&manager->mutex);
                /* copy results back to shared memory */
                pthread_mutex_unlock(&manager->mutex);
            }

            pthread_mutex_lock(&manager->mutex);

            // wait for new data to arrive
            while(manager->workerRunning && !/* new data available*/)
                pthread_cond_wait(&manager->condition, &manager->mutex);

            // check if we should continue running
            if(!manager->workerRunning)
            {
                pthread_mutex_unlock(&manager->mutex);
                break;
            }

            pthread_mutex_unlock(&manager->mutex);
        }

        pthread_exit(NULL);
        return NULL; // just to avoid the missing return statement compiler warning
    }

public:
    Manager() : workerRunning(true) {
        pthread_cond_init(&condition, NULL);
        pthread_mutex_init(&mutex, NULL);
        pthread_attr_init(&workerSettings);
        pthread_attr_setdetachstate(&workerSettings, PTHREAD_CREATE_JOINABLE);
        pthread_create(&worker, &workerSettings, worker_function, (void*)this);
    }

    // this *may* be called repeatedly or very seldom
    void addData(void) {
        pthread_mutex_lock(&mutex);
        /* copy new data into shared memory */
        pthread_cond_signal(&condition);
        pthread_mutex_unlock(&mutex);
    }

    ~Manager()
    {
        // set workerRunning to false and signal the worker
        pthread_mutex_lock(&mutex);
        workerRunning = false;
        pthread_cond_signal(&condition);
        pthread_mutex_unlock(&mutex);

        // wait for the worker to exit
        pthread_join(worker, NULL);

        // cleanup
        pthread_attr_destroy(&workerSettings);
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&condition);
    }
};

我在几个地方对此并不完全确定:

  • Manager 在其构造函数中生成一个新线程这一事实是否被认为是一种不好的做法? (我将只有一个 Manager 对象,所以我想应该没问题)
  • pthread_exit 怎么样 - 我在很多教程中都看到过这个,但我不太明白为什么它应该在那里?我不能简单地返回退出线程的函数吗?我还认为返回 NULL 是死代码,但是 gcc 会在它丢失时发出警告,因为它显然不知道 pthread_exit 已经在此时终止了线程。
  • 关于构造函数 - 我可以在生成线程后立即销毁线程属性对象 (workerSettings) 还是必须在线程的整个生命周期内保持有效?
  • 关于析构函数:这是执行此操作的正确方法吗?

最重要的是:

  • 您有经验的眼睛是否看到那里有任何同步问题?

感谢您的帮助!

最佳答案

你问...

Is the fact that Manager spawns a new thread in its constructor considered a bad practice?

在大多数情况下,RAII 足以处理对象创建和资源获取。在某些情况下,您可能希望实现延迟资源初始化:当您首先构造一个对象,然后再进行初始化时。例如,这可以通过构造函数(默认或参数化)和打开/启动例程来实现。尽管您也可以在 ctor 中执行此操作并通过在进程堆中分配对象(通过 operator new)来实现延迟对象创建。这取决于您的要求、软件设计考虑因素和企业软件开发标准。 因此,您可以在 ctor 中创建一个线程,或者可能希望或需要在应用程序/对象生命周期的后期生成它。

What about the pthread_exit

这不是必需的。它终止调用线程,使其退出状态可用于任何等待线程(即通过 pthread_join())。当任何线程从其启动例程返回时,将发生对 pthread_exit() 的隐式调用。基本上,pthread_exit() 函数提供了一个类似于 exit() 的接口(interface),但基于每个线程(包括取消清理处理程序)。但要注意从取消清理处理程序或从 TSD(线程特定数据区域)中分配的对象的析构函数调用 pthread_exit() - 它可能导致不良副作用。

About the constructor - can i destroy the thread attr object (workerSettings) immediately after spawning the thread or does it have to stay valid for the entire lifetime of the thread?

是的,您可以立即销毁它:它不会影响已经创建的线程。

About the destructor: Is this the right way to do this?

与 ctor 相同:您可以使用 dtor 和关闭/停止例程,或者可以在 dtor 中完成所有操作:取决于您的特定需求(例如对象可重用性等)。只是让 dtor 不抛出。

Do your experienced eyes see any synchronization issues there?

我可能建议使用 pthread_testcancel(),在线程中引入显式取消点,并在控制线程中发出 pthread_cancel() + pthread_join()(应该返回 PTHREAD_CANCELED)来停止子线程,而不是同步变量 workerRunning .当然,如果它适用于您的情况。

关于c++ - PThread 初学者 - 启动、同步、停止工作线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11203194/

有关c++ - PThread 初学者 - 启动、同步、停止工作线程的更多相关文章

  1. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  2. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  5. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  6. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  7. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  8. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  9. ruby - JetBrains RubyMine 3.2.4 调试器不工作 - 2

    使用Ruby1.9.2运行IDE提示说需要gemruby​​-debug-base19x并提供安装它。但是,在尝试安装它时会显示消息Failedtoinstallgems.Followinggemswerenotinstalled:C:/ProgramFiles(x86)/JetBrains/RubyMine3.2.4/rb/gems/ruby-debug-base19x-0.11.30.pre2.gem:Errorinstallingruby-debug-base19x-0.11.30.pre2.gem:The'linecache19'nativegemrequiresinstall

  10. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

随机推荐