如何在互斥锁中优先考虑特权线程?

2024-01-18

首先:我完全是互斥/多线程编程的新手,所以 提前对任何错误表示歉意...

我有一个运行多个线程的程序。线程(通常每 cpu核心)做了很多 计算和“思考”,然后有时他们决定打电话给 更新一些统计数据的特定(共享)方法。 统计更新的并发性是通过使用互斥体来管理的:

stats_mutex.lock();
common_area->update_thread_stats( ... );
stats_mutex.unlock();

现在来说说问题。 在所有这些线程中,有一个特定的线程几乎需要
实时优先级,因为它是唯一实际运行的线程。

对于“几乎实时优先级”我的意思是:

假设线程 t0 是“特权线程”,t1....t15 是普通线程 现在发生的是:

  • 线程 t1 获取锁。
  • 线程t2、t3、t0调用lock()方法并等待成功。
  • 线程 t1 调用unlock()
  • 线程 t2、t3、t0 中的一个(随机,据我所知)成功获取 锁,其他的继续等待。

我需要的是:

  • 线程 t1 获取锁。
  • 线程t2、t3、t0调用lock()方法并等待成功。
  • 线程 t1 调用unlock()
  • 线程 t0 获取锁,因为它具有特权

那么,做这件事最好的(可能是最简单的)方法是什么?

我的想法是有一个名为的 bool 变量 “特权需要锁”。

但我认为我需要另一个互斥体来管理对该变量的访问...我不 知道这是否是正确的方法...

附加信息:

  • 我的线程使用 C++11(从 gcc 4.6.3 开始)
  • 代码需要在 Linux 和 Windows 上运行(但目前仅在 Linux 上进行测试)。
  • 锁定机制的性能不是问题(我的性能问题在于内部线程计算,线程数总是很低,每个CPU核心最多一两个)

任何想法表示赞赏。 谢谢


以下解决方案有效(三种互斥方式):

#include <thread>
#include <iostream>
#include <mutex>
#include "unistd.h"

std::mutex M;
std::mutex N;
std::mutex L;

void lowpriolock(){
  L.lock();
  N.lock();
  M.lock();
  N.unlock();
}

void lowpriounlock(){
  M.unlock();
  L.unlock();
}

void highpriolock(){
  N.lock();
  M.lock();
  N.unlock();
}

void highpriounlock(){
  M.unlock();
}

void hpt(const char* s){
  using namespace std;
  //cout << "hpt trying to get lock here" << endl;
  highpriolock();
  cout << s << endl;
  sleep(2);
  highpriounlock();
}

void lpt(const char* s){
  using namespace std;
  //cout << "lpt trying to get lock here" << endl;
  lowpriolock();
  cout << s << endl;
  sleep(2);
  lowpriounlock();
}

int main(){
std::thread t0(lpt,"low prio t0 working here");
std::thread t1(lpt,"low prio t1 working here");
std::thread t2(hpt,"high prio t2 working here");
std::thread t3(lpt,"low prio t3 working here");
std::thread t4(lpt,"low prio t4 working here");
std::thread t5(lpt,"low prio t5 working here");
std::thread t6(lpt,"low prio t6 working here");
std::thread t7(lpt,"low prio t7 working here");
//std::cout << "All threads created" << std::endl;
t0.join();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
t7.join();
return 0;
}

按照建议尝试了以下解决方案,但它does not工作(使用“ g++ -std=c++0x -o test test.cpp -lpthread”编译):

#include <thread>
#include <mutex>

#include "time.h"
#include "pthread.h"

std::mutex l;

void waiter(){
  l.lock();
  printf("Here i am, waiter starts\n");
  sleep(2);
  printf("Here i am, waiter ends\n");
  l.unlock();
}

void privileged(int id){
  usleep(200000);
  l.lock();
  usleep(200000);
  printf("Here i am, privileged (%d)\n",id);
  l.unlock();  
}

void normal(int id){
  usleep(200000);
  l.lock();
  usleep(200000);
  printf("Here i am, normal (%d)\n",id);
  l.unlock();    
}

int main(){
  std::thread tw(waiter);
  std::thread t1(normal,1);
  std::thread t0(privileged,0);
  std::thread t2(normal,2);

  sched_param sch;
  int policy; 

  pthread_getschedparam(t0.native_handle(), &policy, &sch);
  sch.sched_priority = -19;
  pthread_setschedparam(t0.native_handle(), SCHED_FIFO, &sch);

  pthread_getschedparam(t1.native_handle(), &policy, &sch);
  sch.sched_priority = 18;
  pthread_setschedparam(t1.native_handle(), SCHED_FIFO, &sch);

  pthread_getschedparam(t2.native_handle(), &policy, &sch);
  sch.sched_priority = 18;
  pthread_setschedparam(t2.native_handle(), SCHED_FIFO, &sch);
  
  tw.join();
  t1.join();
  t0.join();
  t2.join();

  return 0;  
}

我可以想到三种仅使用线程原语的方法:

三重互斥体

三个互斥体在这里可以工作:

  • 数据互斥体('M')
  • 下一个访问互斥体('N'),以及
  • 低优先级访问互斥体('L')

访问模式是:

  • 低优先级线程:锁定 L、锁定 N、锁定 M、解锁 N、{ do stuff }、解锁 M、解锁 L
  • 高优先级线程:锁定 N,锁定 M,解锁 N,{ do stuff },解锁 M

这样,对数据的访问就受到保护,并且高优先级线程可以领先于低优先级线程来访问数据。

互斥量、条件变量、原子标志

执行此操作的原始方法是使用条件变量和原子:

  • Mutex M;
  • 康德瓦尔C;
  • 原子 bool hpt_waiting;

数据访问模式:

  • 低优先级线程:锁定 M,while (hpt_waiting) 在 M 上等待 C,{ do stuff },广播 C,解锁 M
  • 高优先级线程: hpt_waiting := true, lock M, hpt_waiting := false, { do stuff }, 广播 C, 解锁 M

互斥量、条件变量、两个非原子标志

或者,您可以将两个非原子布尔值与 condvar 一起使用;在此技术中,互斥体/condvar 保护标志,并且数据不是由互斥体而是由标志保护:

  • Mutex M;

  • 康德瓦尔C;

  • 布尔数据保持,hpt_等待;

  • 低优先级线程:锁定 M,while (hpt_waiting 或 data_held) 在 M 上等待 C,data_held := true,解锁 M,{ do stuff },锁定 M,data_held := false,广播 C,解锁 M

  • 高优先级线程:lock M、hpt_waiting := true、while (data_held) wait C on M、data_held := true、unlock M、{ do stuff }、lock M、data_held := false、hpt_waiting := false、广播 C ,解锁M

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在互斥锁中优先考虑特权线程? 的相关文章

  • C#动态支持吗?

    看完之后这个帖子 https stackoverflow com questions 2674906 when should one use dynamic keyword in c sharp 4 0k和链接 我还有 2 个问题 问题 1
  • 32 位应用程序的特征最大矩阵大小

    所以 我正在寻找Eigen http eigen tuxfamily org index php title Main Page当我尝试声明大于 10000x10000 的矩阵时 包崩溃 我需要声明一个像这样的矩阵 可靠地大约有 13000
  • Clang 编译器 (x86):80 位长双精度

    我正在尝试在 x86 Windows 平台上使用本机 80 位长双精度 海湾合作委员会选项 mlong double 80 https gcc gnu org onlinedocs gcc x86 Options html似乎不适用于 cl
  • 对齐 GridView 中的行值

    我需要在 asp net 3 5 中右对齐 gridview 列中的值 我怎样才能做到这一点
  • 显示异常时的自定义错误消息:从客户端检测到潜在危险的 Request.Form 值

    我在我的 Web 应用程序中使用 ASP NET 的登录控件 当发生此异常时 我想在标签上显示一种有趣的错误类型System Web HttpRequestValidationException A potentially dangerou
  • 如何使用recv()检测客户端是否仍然连接(并且没有挂起)?

    我写了一个多客户端服务器程序C on SuSE Linux 企业服务器 12 3 x86 64 我为每个客户端使用一个线程来接收数据 我的问题是 我使用一个终端来运行服务器 并使用其他几个终端来运行服务器telnet到我的服务器 作为客户端
  • 从多个类访问串行端口

    我正在尝试使用串行端口在 arduino 和 C 程序之间进行通信 我对 C 编程有点陌生 该程序有多种用户控制形式 每一个都需要访问串口来发送数据 我需要做的就是从每个类的主窗体中写入串行端口 我了解如何设置和写入串行端口 这是我的 Fo
  • 暂停下载线程

    我正在用 C 编写一个非常简单的批量下载程序 该程序读取要下载的 URL 的 txt 文件 我已经设置了一个全局线程和委托来更新 GUI 按下 开始 按钮即可创建并启动该线程 我想要做的是有一个 暂停 按钮 使我能够暂停下载 直到点击 恢复
  • 无法将类型“System.IO.Stream”隐式转换为“Java.IO.InputStream”

    我提到了一些类似的问题 但没有一个涉及IO 当我使用时 我在java中使用了相同的代码Eclipse 那次就成功了 但现在我尝试在中使用这段代码Mono for Android C 它不起作用 我正在尝试运行此代码来创建一个InputStr
  • 生产代码中的 LRU 实现

    我有一些 C 代码 需要使用 LRU 技术实现缓存替换 目前我知道两种实现LRU缓存替换的方法 每次访问缓存数据时使用时间戳 最后比较替换时的时间戳 使用缓存项的堆栈 如果最近访问过它们 则将它们移动到顶部 因此最后底部将包含 LRU 候选
  • 如何在c#中的内部类中访问外部类的变量[重复]

    这个问题在这里已经有答案了 我有两个类 我需要声明两个类共有的变量 如果是嵌套类 我需要访问内部类中的外部类变量 请给我一个更好的方法来在 C 中做到这一点 示例代码 Class A int a Class B Need to access
  • 为什么我不应该对不是由 malloc() 分配的变量调用 free() ?

    我在某处读到 使用它是灾难性的free删除不是通过调用创建的对象malloc 这是真的 为什么 这是未定义的行为 永远不要尝试它 让我们看看当您尝试时会发生什么free 自动变量 堆管理器必须推断出如何获取内存块的所有权 为此 它要么必须使
  • 将构建日期放入“关于”框中

    我有一个带有 关于 框的 C WinForms 应用程序 我使用以下方法将版本号放入 关于 框中 FileVersionInfo GetVersionInfo Assembly GetExecutingAssembly Location F
  • System.Runtime.InteropServices.COMException(0x80040154):[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我在 C 项目中遇到异常 System Runtime InteropServices COMException 0x80040154 检
  • g++ 对于看似不相关的变量“警告:迭代...调用未定义的行为”

    考虑以下代码strange cpp include
  • 将代码拆分为标头/源文件

    我从 Asio 的示例页面中获取了以下代码 class tcp connection public boost enable shared from this
  • 是否可以有一个 out ParameterExpression?

    我想定义一个 Lambda 表达式out范围 有可能做到吗 下面是我尝试过的 C Net 4 0 控制台应用程序的代码片段 正如您在 procedure25 中看到的 我可以使用 lambda 表达式来定义具有输出参数的委托 但是 当我想使
  • 当前的 x86 架构是否支持非临时加载(来自“正常”内存)?

    我知道有关此主题的多个问题 但是 我没有看到任何明确的答案或任何基准测量 因此 我创建了一个处理两个整数数组的简单程序 第一个数组a非常大 64 MB 第二个数组b很小 无法放入 L1 缓存 程序迭代a并将其元素添加到相应的元素中b在模块化
  • 结构体指针的动态数组

    我必须使用以下代码块来完成学校作业 严格不进行任何修改 typedef struct char firstName char lastName int id float mark pStudentRecord pStudentRecord
  • 使用 C# 从 DateTime 获取日期

    愚蠢的问题 给定日期时间中的日期 我知道它是星期二 例如我如何知道它的 tue 2 和 mon 1 等 Thanks 您正在寻找星期几 http msdn microsoft com en us library system datetim

随机推荐

  • open_basedir 的影响和子域限制

    出于安全原因 我已将我的yiihtml 根目录下的文件夹 所以我的结构如下所示 conf httpdocs httpsdocs yii 运行该网站时 我收到错误 open basedir 限制yii php这是由index php out
  • AppBar Material UI 问题

    我对 Material UI 库还很陌生 但到目前为止我真的很喜欢它 但是 我遇到了 AppBar 组件覆盖在我的其他内容上的问题 我目前有
  • 维基百科上的汉字编码是什么?

    我在维基百科上查看中文字符的编码 但无法弄清楚它们正在使用什么 例如 的 被编码为 E7 9A 84 see here http upload wikimedia org wikipedia commons thumb a ae E7 9A
  • Maven - 检测同一依赖项的多个版本

    我刚刚经历了我的 Maven 项目的两个直接依赖项的情况 它们具有特定传递依赖项的两个不同版本 在我的特定情况下 我直接依赖于以下内容
  • 我可以将节点文本包装在 WinForms TreeView 中吗

    ASP NET TreeView 有一个 NodeWrap 属性 是否有在 WinForms TreeView 中完成相同操作的等效方法 EDIT 感谢您对其他控件的建议 不幸的是我的客户不允许使用第三方控件 这似乎不可能 您可能会寻找具有
  • CreateProcess 和奇怪的 nslookup 错误

    我有一个经常使用的 api 例程来捕获 dos 输出 最近发现了一个奇怪的错误 它似乎不允许 dns 调用 例如 nslookup 将返回 服务器无响应 错误 服务器 未知 如果您向其提供 IP 地址 Ping 将起作用 但如果它必须进行
  • Postgres-必须 to_timestamp() 忽略/不读取日期/时间字符串中间的特定字符

    我有原始文本列 其值类似于 2012 07 26T10 33 34 和 2012 07 26T10 56 16 在Java中使用Joda Time我可以通过调用轻松地将其转换为日期 从日期转换 new SimpleDateFormat yy
  • 当存在两种同名类型时,如何消除监视窗口中类型的歧义

    在监视窗口中 我试图查看TaskScheduler Current 但它向我显示以下错误 The type System Threading Tasks TaskScheduler exists in both CommonLanguage
  • 获取特定值的数组索引

    ArrayIndex Value Running total 0 6 6 1 1 7 2 6 13 3 2 15 I array index V value R Running total 例如 我需要为给定的运行总计选择适当的索引 12
  • Android 中的保留字列表

    我目前正在开发另一个 Android 应用程序的界面设计过程中 我似乎再次尝试使用资源的保留字 无论是可绘制对象还是布局 据我所知 您需要了解一组规则 不允许大写 除下划线外没有任何符号 没有数字 除了这些 如果我错了请纠正我 我think
  • 如何在 OSX Snow Leopard 10.6 上安装 perl DBD::Oracle

    我正在尝试从运行 OSX 10 6 雪豹的英特尔 Mac 连接到远程系统上的 Oracle 10 2 0 4 我尝试使用 perl CPAN 安装 DBD Oracle DBI 工作正常 但出现编译错误 有人可以提供一个易于遵循的指南吗 在
  • 通过类函数返回引用并返回 C++ 中的整个对象?

    Vector 类中的运算符重载 CVector CVector operator CVector param CVector temp temp x x param x temp y y param y return temp 并主要 CV
  • 如何在Excel和C#之间将“double”转换为“datetime”

    我有一个 C 程序 需要创建一个 excel 对象 并执行一些操作 这是我的代码的一部分 c code workSheet Cells 1 1 2012 9 20 asign 2012 9 20 to cell 1 1 in Excel d
  • 为什么 gradle lint 认为省略号字符“…”比“…”更具可读性?

    我在 string xml 中定义了一个字符串 XXX 并遇到了 gradle lint 问题 Replace with ellipsis character 8230 Explanation Ellipsis string can be
  • 在 python 中使用 grep

    有一个文件 query txt 其中包含一些关键字 短语 需要使用 grep 与其他文件进行匹配 以下代码的最后三行工作正常 但是当在 while 循环内使用相同的命令时 它会进入无限循环或其他东西 即不响应 import os f ope
  • 将 Google 云端硬盘推送通知设置为永不过期

    我已经阅读了用于推送通知的 Google Drive API 似乎有一种方法可以将通道设置为永不过期 但我找不到有关如何执行此操作的文档 我尝试将 ttl 参数设置为 0 和 null 两次 API 返回的过期时间都是从调用时间起 3600
  • 从 C# 运行 Powershell 会出现错误:“此系统上禁用运行脚本”

    在我的 C 应用程序中 我尝试创建一个RunSpace调用一些 Powershell 脚本 然而 当它到达实际创建它的代码时 它会失败并出现以下错误 var implementedHost new implementedPSHost usi
  • 运行exe后如何返回退出代码?

    我创建了一个控制台应用程序来验证函数 并且我需要使用 vbscript 来执行该应用程序 执行此 exe 后 无论函数返回成功与否 我都想返回退出代码 如何在 net 中返回状态或退出代码 我假设您正在编写 C 或 VB NET 在任何一种
  • Perl 中的匿名哈希是什么?

    hash Man gt Bill Woman gt Mary Dog gt Ben Perl 的 匿名散列 到底有什么作用 它是对可以存储在标量变量中的哈希的引用 它与常规哈希完全相同 只是大括号不同 创建一个参考到一个哈希值 请注意这些示
  • 如何在互斥锁中优先考虑特权线程?

    首先 我完全是互斥 多线程编程的新手 所以 提前对任何错误表示歉意 我有一个运行多个线程的程序 线程 通常每 cpu核心 做了很多 计算和 思考 然后有时他们决定打电话给 更新一些统计数据的特定 共享 方法 统计更新的并发性是通过使用互斥体