我正在尝试在 Linux 上使用健壮的互斥锁来保护进程之间的资源,但在某些情况下它们似乎并不以“健壮”的方式运行。我所说的“稳健”方式是指如果拥有锁的进程已终止,pthread_mutex_lock 应该返回 EOWNERDEAD。
这是它不起作用的场景:
2 个进程 p1 和 p2。 p1 创建健壮的互斥量并等待它(在用户输入之后)。 p2 有 2 个线程:线程 1 映射到互斥量并获取它。线程 2(在线程 1 获得互斥量之后)也映射到相同的互斥量并等待它(因为线程 1 现在拥有它)。另请注意,在 p2-thread1 已经获得互斥锁后,p1 开始等待它。
现在,如果我们终止 p2,p1 永远不会解除阻塞(意味着它的 pthread_mutex_lock 永远不会返回),这与 p1 应该解除阻塞并出现 EOWNERDEAD 错误的所谓“稳健性”相反。
代码如下:
p1.cpp:
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
struct MyMtx {
pthread_mutex_t m;
};
int main(int argc, char **argv)
{
int r;
pthread_mutexattr_t ma;
pthread_mutexattr_init(&ma);
pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED);
pthread_mutexattr_setrobust_np(&ma, PTHREAD_MUTEX_ROBUST_NP);
int fd = shm_open("/test_mtx_p", O_RDWR|O_CREAT, 0666);
ftruncate(fd, sizeof(MyMtx));
MyMtx *m = (MyMtx *)mmap(NULL, sizeof(MyMtx),
PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
//close (fd);
pthread_mutex_init(&m->m, &ma);
puts("Press Enter to lock mutex");
fgetc(stdin);
puts("locking...");
r = pthread_mutex_lock(&m->m);
printf("pthread_mutex_lock returned %d\n", r);
puts("Press Enter to unlock");
fgetc(stdin);
r = pthread_mutex_unlock(&m->m);
printf("pthread_mutex_unlock returned %d\n", r);
puts("Before pthread_mutex_destroy");
r = pthread_mutex_destroy(&m->m);
printf("After pthread_mutex_destroy, r=%d\n", r);
munmap(m, sizeof(MyMtx));
shm_unlink("/test_mtx_p");
return 0;
}
p2.cpp:
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
struct MyMtx {
pthread_mutex_t m;
};
static void *threadFunc(void *arg)
{
int fd = shm_open("/test_mtx_p", O_RDWR|O_CREAT, 0666);
ftruncate(fd, sizeof(MyMtx));
MyMtx *m = (MyMtx *)mmap(NULL, sizeof(MyMtx),
PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
sleep(2); //to let the first thread lock the mutex
puts("Locking from another thread");
int r = 0;
r = pthread_mutex_lock(&m->m);
printf("locked from another thread r=%d\n", r);
}
int main(int argc, char **argv)
{
int r;
int fd = shm_open("/test_mtx_p", O_RDWR|O_CREAT, 0666);
ftruncate(fd, sizeof(MyMtx));
MyMtx *m = (MyMtx *)mmap(NULL, sizeof(MyMtx),
PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
//close (fd);
pthread_t tid;
pthread_create(&tid, NULL, threadFunc, NULL);
puts("locking");
r = pthread_mutex_lock(&m->m);
printf("pthread_mutex_lock returned %d\n", r);
puts("Press Enter to terminate");
fgetc(stdin);
kill(getpid(), 9);
return 0;
}
首先,运行 p1,然后运行 p2 并等待它打印“Locking from another thread”。在 p1 的 shell 上按 Enter 锁定互斥体,然后在 p2 的 shell 上按 Enter 终止 p2,或者您可以用其他方式杀死它。您会看到 p1 打印“locking...”并且 pthread_mutex_lock 永远不会返回。
这个问题其实不是一直都会发生,貌似要看时间。如果在 p1 开始锁定之后和终止 p2 之前让一段时间过去,有时它会起作用并且 p2 的 pthread_mutex_lock 返回 130 (EOWNERDEAD)。但是,如果您在 p1 开始等待互斥锁后立即或短时间内终止 p2,p1 将永远不会解除阻塞。
有没有人遇到过同样的问题?
最佳答案
刚刚验证了 glibc 版本的行为:2.11.1 在 Linux 内核 2.6.32 和更新版本上。
我的第一个发现:如果你在 p2 中的“从另一个线程锁定”之前(在 2 秒内)在 p1 中按下 Enter,那么强大的互斥锁工作正常。正如人们所期望的那样。结论:WAITING线程的顺序很重要。
第一个等待线程被唤醒。不幸的是,当时 p2 中的线程被杀死了。
参见 https://lkml.org/lkml/2013/9/27/338问题的描述。
我不知道是否有内核修复/补丁。甚至根本不知道它是否被视为错误。
然而,似乎有一个解决整个困惑的方法。将强大的互斥体与 PTHREAD_PRIO_INHERIT 结合使用:
pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_INHERIT);
内核内部 (futex.c) 而不是 handle_futex_death() exit_pi_state_list() 中的一些其他机制确实处理其他互斥等待者的唤醒。它似乎解决了问题。
关于c++ - 具有强大互斥锁的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20557288/
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file
我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe
在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie