我有一个程序可以创建许多线程并运行,直到电源关闭到嵌入式计算机,或者用户使用kill或ctrlc终止进程.
这是一些代码以及main()的外观.
static int terminate = 0; // does this need to be volatile?
static void sighandler(int signum) { terminate = 1; }
int main() {
signal(SIGINT, sighandler);
// ...
// create objects, spawn threads + allocate dynamic memory
// ...
while (!terminate) sleep(2);
// ...
// clean up memory, close threads, etc.
// ...
signal(SIGINT, SIG_DFL); // is this necessary?
}
Run Code Online (Sandbox Code Playgroud)
我想知道一些事情:
是否需要任何信号处理?
我在这个帖子中读到了"Linux C catch kill信号以便正常终止",显然操作系统会为我处理清理工作.因此,我可以只用无限循环替换信号处理程序,让操作系统优雅地退出线程,取消分配内存等吗?
关于清洁终止,我还需要关注其他任何信号吗?这个主题"SIGINT如何与其他终止信号相关?" ,列出我可能关注的所有信号,但有多少实际需要处理是有用的?
我的示例中的terminate变量是否必须是volatile?我已经看到很多这个变量是易变的例子,而其他的变量则不是.
我已经读过, …
假设我有一个类需要一些常量来运行.几个成员函数需要使用这些常量.使用#define是不受欢迎的,因为它可能导致冲突.常量是8位或16位的十六进制模式,存储为uint8_t或uint16_t.这些常量也不会从类的实例更改为实例,因此只需要一个常量副本就可以保存内存(尽管内存非常少).
是否存在任何不正确的,或者更好的方式来实现上述内容,而不是简单地执行以下操作:
// mycode.h
// .......
class myclass {
private:
static const uint16_t kMyClassConstant_ = 0xBEEF;
// .......
};
Run Code Online (Sandbox Code Playgroud)
在此先感谢您的帮助.
每隔一段时间,我偶然发现一些代码,我正在考虑我的代码风格.今天是那种日子之一...
我知道你为什么要使用范围运算符来定义全局范围.实际上,这里没有范围的范围解析运算符是一个很好的链接告诉你为什么.
但是,我看到了一些让我今天想到的东西.所有有问题的类都包含在项目的命名空间中(好!),但我确实看到了全局范围运算符的大量使用.也就是说,它被用于C库中的所有东西(除了uint8_t等之外......是的,程序员使用了这个库的.h版本,因为他们运行的g ++版本显然仍然对新的C++发出警告标准).这有用吗?我认为这就像浪费字符一样(让我想起使用这个指针......除了复制构造函数和赋值运算符的情况,它有助于澄清哪个对象是哪个).我错过了什么吗?当然,有人可以到处找到usleep()或stderr(我看到"::"的最多用法)的名字,但是赢得了' 他们知道这样做可能会破坏一些可怕的东西吗?你在什么时候用范围操作符说"搞砸",只是告诉自己,在命名空间中以某种方式命名函数的人会遇到麻烦?
所以我的问题是......在这种情况下使用全局范围运算符的"正确"(主观我理解)方式是什么?如果未包含在std或您自己的命名空间中的所有内容都明确定义了全局范围吗?我倾向于小心谨慎并使用"std ::"来避免使用指令,但是在这里使用全局范围运算符可以获得什么?我倾向于认为为了清晰起见,它确实导致我们没有从当前命名空间获得有问题的变量或函数,但我在包含它而不是今天的开发之间徘徊.
一如既往,感谢您的帮助和指导,因为我希望使我的代码更清晰,更易读,并且(当然)更加出色.
在我使用C/C++时,在.cpp/.c文件中包含.h文件时,我遇到了处理#include指令文件路径的不同方法.Google样式指南暗示在#include中使用部分文件路径.话虽这么说,我目前正在开发一个项目(尽管是一个小项目),当我"继承"代码时,我为我准备了一个精心布局的Makefile(用于G ++)和结构.也就是说,有一个名为/ project_name的目录,里面是Makefile和几个子目录.例如,/ project_name/inc包含.h文件,/ project_name/src包含.cpp文件.Makefile设置为查看每个子目录以编译源代码.
我的问题是,给定目录结构和Makefile,#include的"首选"方法是什么.我成功使用的两个备选方案如下所示.
我还缺少其他选择吗?
我下周将在C++ 11/14上上课,需要验证我的设计工具是最新的,并且实际上可以编译C++ 11/14.
我可以用什么最简单的代码来验证我是否可以在我的Linux机器上编译和执行C++ 11/14代码?我知道我需要GCC 4.9.X或更好,但我想确保在我出现之前一切都在疯狂.
谢谢您的帮助.
看完这里的内核文档后:https://www.kernel.org/doc/Documentation/PCI/pci.txt关于设置和拆除PCI驱动程序的函数调用的顺序,我很遗憾.
我有两个问题:
对于设置,pci_enable_device()总是来之前
pci_request_regions()?文档似乎指出了这个事实,但确实说明:
OS BUG:在启用这些资源之前,我们不会检查资源分配.如果我们
pci_request_resources()在打电话之前打电话,序列会更有意义pci_enable_device().目前,当两个设备分配了相同的范围时,设备驱动程序无法检测到错误.这不是常见问题,不太可能很快修复.这已经在之前讨论过,但在2.6.19之后没有改变:http://lkml.org/lkml/2006/3/2/194
但是,在快速浏览了几个驱动程序的源代码之后,我们的共识是pci_enable_device()始终是第一位的.这些电话中的哪一个应该首先出现,为什么?
为了拆掉司机,我更加困惑.假设pci_enable_device()是第一个,我希望你在调用pci_release_regions()之前首先调用pci_disable_device()(即遵循一些对称性).但是,内核文档说这pci_release_regions()应该是最后的.让事情变得更复杂的是,我看了很多司机,而且几乎所有司机都有pci_release_regions()过pci_disable_device(),就像我期望的那样.但是,我偶然发现了这个驱动程序:https://elixir.bootlin.com/linux/v4.12/source/drivers/infiniband/hw/hfi1/pcie.c(代码转载如下).
void hfi1_pcie_cleanup(struct pci_dev *pdev)
{
pci_disable_device(pdev);
/*
* Release regions should be called after the disable. OK to
* call if request regions has not been called or failed.
*/
pci_release_regions(pdev);
}
Run Code Online (Sandbox Code Playgroud)
在拆除驱动程序时应该首先使用哪种功能?看来内核中的驱动程序本身无法达成一致.
我有一个具有一些软实时要求的项目.我有两个进程(我编写的程序)进行一些数据采集.在任何一种情况下,我都需要不断读入正在进入并处理它的数据.
第一个程序是严格的线程,第二个程序使用一个应该是线程的库,但我不知道幕后发生了什么.每个程序都由用户执行,并且(默认情况下)我看到每个程序的优先级为20,漂亮的值为0.每个程序使用大约30%的CPU.
就目前而言,两个进程都必须与一些后台进程争用,我想尽可能地为我的两个程序提供最好的CPU.我的主要问题是我有一个与之交谈的设备,它有一个64字节的硬件缓冲区,如果我没有及时读取它,我会得到溢出.我注意到这种情况每运行2-3小时就会发生一次.
根据我的研究(http://oreilly.com/catalog/linuxkernel/chapter/ch10.html),似乎有三种方法可以优先使用:
将nice值设置为较小的数字,因此为每个进程提供更多优先级.我可以使用nice命令在不对代码进行任何修改(或使用系统调用)的情况下执行此操作.
将sched_setscheduler()用于特定调度策略的整个过程.
使用pthread_setschedparam()分别设置每个pthread.
我遇到了以下障碍:
假设我选择3,如何防止低优先级线程被饿死?是否还有一种方法可以确保共享锁将优先级较低的线程提升到更高的优先级?假设我有一个实时的线程,SCHED_RR并且它与默认的SCHED_OTHER线程共享一个锁.当SCHED_OTHER线程获得锁定时,我希望它执行@更高优先级以释放锁定.我如何确保这一点?
如果SCHED_RR的一个线程创建另一个线程,新线程是自动SCHED_RR,还是我需要指定它?如果我有一个我已设置为SCHED_RR的进程,它的所有线程是否自动遵循此策略怎么办?如果SCHED_RR的进程产生子进程怎么办,它是否太自动SCHED_RR?
鉴于代码仅占用CPU的60%,这是否有任何问题?或者是否仍然存在CPU与后台进程共享的问题,我应该关注并可能导致我的缓冲区溢出?
抱歉这个冗长的问题,但我觉得它需要一些背景信息.在此先感谢您的帮助.
我有一个位置选项(文件名),我希望它是最后一个选项.基本上,用户可以在命令行上传递一堆东西,并且还使用-F作为文件名.但是,我希望用户也能够将文件名放在最后.
例如
./program --var 3 /path/to/file
Run Code Online (Sandbox Code Playgroud)
我当前实现的代码允许调用者将文件名放在命令行的任何位置.无论如何强迫位置参数总是在"常规"之后?
以下是我设置位置参数的方法:
pos_opts_desc.add("filename", -1);
Run Code Online (Sandbox Code Playgroud)
并解析命令行:
store(
command_line_parser(argc, argv).options(opts_desc).postional(pos_opts_desc).run(),
opts_var_map);
Run Code Online (Sandbox Code Playgroud)
在此先感谢您的帮助.
编辑添加:
我完全可以在命令行的任何地方指定-F.但是,如果设置是通过位置选项完成的,我想确保位置选项位于最后.
我目前正在使用Xilinx XDMA驱动程序(请参阅此处获取源代码:XDMA Source),并且我试图让它运行(在你问之前:我已经联系了我的技术支持联系人,Xilinx论坛上到处都是人有同样的问题).但是,我可能在Xilinx的代码中找到了一个障碍,这对我来说可能是一个交易破坏者.我希望有一些我不会考虑的事情.
首先,驱动程序有两种主要模式,AXI-Memory Mapped(AXI-MM)和AXI-Streaming(AXI-ST).对于我的特定应用,我需要AXI-ST,因为数据将持续从设备流出.
编写驱动程序以利用分散 - 收集列表.在AXI-MM模式下,这是有效的,因为读取是相当随机的事件(即,没有数据流出设备,而用户空间应用程序只是在需要时请求数据).因此,建立DMA传输,传输数据,然后拆除传输.这是一个组合get_user_pages(),pci_map_sg()和pci_unmap_sg().
对于AXI-ST来说,事情变得奇怪,源代码远非正统.驱动程序分配一个循环缓冲区,数据意味着连续流入.此缓冲区的大小通常有些大(我的设置大小为32MB),因为您希望能够处理用户空间应用程序忘记驱动程序的瞬态事件,然后可以解决传入的数据.
这里的事情变得很糟糕......循环缓冲区是使用分配的,vmalloc32()并且来自该分配的页面的映射方式与用户空间缓冲区处于AXI-MM模式(即使用pci_map_sg()接口)的方式相同.其结果是,因为循环缓冲器的设备和CPU之间共享,每个read()呼叫需要我打电话pci_dma_sync_sg_for_cpu()和pci_dma_sync_sg_for_device(),这绝对会破坏我的表现(我不能与设备跟不上!),因为这会作用于整个缓冲区.有趣的是,Xilinx从未在代码中包含这些同步调用,因此我首先知道在编辑测试脚本以在退出之前尝试多个DMA传输并且生成的数据缓冲区已损坏时,我遇到了问题.
结果,我想知道如何解决这个问题.我已经考虑过重写代码来构建我自己分配的缓冲区pci_alloc_consistent()/dma_alloc_coherent(),但这说起来容易做起来难.也就是说,代码被设计为假设在任何地方使用分散 - 收集列表(在分散 - 收集列表和FPGA理解的内存描述符之间似乎存在奇怪的专有映射).
有没有其他API调用我应该知道?我是否可以pci dma_sync_single_for_cpu()通过某种转换机制使用"单一"变体(即)来同步整个缓冲区?或者,是否有一些函数可以使循环缓冲区分配vmalloc()相干?
因此,基于粗略搜索,我已经知道从构造函数中调用虚函数(纯函数或其他函数)是不行的.我重新构建了我的代码,以确保我没有这样做.虽然这会导致我的类的用户在他们的代码中添加一个额外的函数调用,但这真的不是什么大不了的事.也就是说,它们不是在循环中调用构造函数,而是调用函数(事实上!)来提高代码的性能,因为我们没有每次构建和销毁相关对象的内务处理.
但是,我偶然发现了一些有趣的事情......
在抽象类中我有这样的东西:
// in AbstractClass.h:
class AbstractClass {
public:
AbstractClass() {}
virtual int Func(); //user can override
protected:
// Func broken up, derived class must define these
virtual int Step1() = 0;
virtual int Step2() = 0;
virtual int Step3() = 0;
// in AbstractClass.cpp:
int AbstractClass::Func() {
Step1();
// Error checking goes here
Step2();
// More error checking...
// etc...
}
Run Code Online (Sandbox Code Playgroud)
基本上,有一个共同的结构,纯虚函数大多数时间都遵循,但如果它们不是Func()是虚拟的,并允许派生类指定顺序.但是,每个步骤都必须在派生类中实现.
我只是想确保在Func()函数调用纯虚函数时,没有什么我在这里做错了.也就是说,使用基类,如果你调用StepX(),就会发生不好的事情.但是,通过创建派生对象然后在该派生对象上调用Func()(例如MyDerivedObject.Func();)来使用该类,该派生对象应该正确地重载所有纯虚函数.
通过这种方法,我有什么遗漏或做错了吗?谢谢您的帮助!