是否有任何可移植的方式(在POSIX系统上)来确定文件描述符是否可搜索?我的想法是使用lseek(fd, 0, SEEK_CUR);并检查返回值是否为-1,但我不确定这是否会给出假阴性或误报.使用fstat和假设哪些类型的文件是可搜索/不可搜索的并不是一个好主意.还有其他想法吗?
创建可变参数宏的技巧是什么FOO(a1, a2, a3,..., an),它可以扩展到您选择的任何预选有界范围内的FOOn(a1, a2, a3,..., an)值n?也就是说,FOO(a)应该扩展FOO1(a),FOO(a, b, c)对FOO3(a, b, c)等,我知道有一个标准的把戏,但我似乎无法找到它.
请随意将此问题标记为副本,如果答案中还有其他问题,请将其关闭.我怀疑有,但我找不到它.
C99标准以6.5.2美元计价.
在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的计算来修改一次.此外,先前的值应该只读以确定要存储的值.
(我强调)
它继续指出,以下示例是有效的(一开始看起来很明显)
a[i] = i;
Run Code Online (Sandbox Code Playgroud)
虽然它没有明确说明是什么a和i是什么.
虽然我相信它没有,但我想知道这个例子是否涵盖以下情况:
int i = 0, *a = &i;
a[i] = i;
Run Code Online (Sandbox Code Playgroud)
这不会改变值i,而是访问值i来确定放置值的地址.或者我们分配一个i已存储的值是无关紧要的i?请说清楚.
奖金问题; 怎么样a[i]++还是a[i] = 1?
C11 6.7.3类型限定词,第7段,内容如下:
具有volatile限定类型的对象可能以实现未知的方式进行修改,或者具有其他未知的副作用.因此,任何涉及这种对象的表达都应严格按照抽象机的规则进行评估,如5.1.2.3所述.
在以下示例中,第三行中访问的对象是否受上述规则约束?
int x;
volatile int *p = &x;
*p = 42;
Run Code Online (Sandbox Code Playgroud)
换句话说,左值*p是否具有类型volatile int意味着正在访问易失性对象,或者p指向非易失性对象的事实是否x意味着编译器可以利用这些知识进行优化并省略易失性访问?
由于它可能是有意义的,我感兴趣的特定用例不在普通C的范围内; 它涉及使用pre-C11结构(可以是内联asm或简称为黑盒子)进行线程同步的原子,用于原子比较和交换,具有以下习语:
do {
tmp = *p;
new = f(tmp);
} while (atomic_cas(p, tmp, new) != success);
Run Code Online (Sandbox Code Playgroud)
在这里,指针p就会有型volatile int *,但我很担心会发生什么,当实际指向的对象是非易失性的,特别是是否编译器可以单址变换,以*p从tmp = *p为以下形式的两次存取:
do {
new = f(*p);
} while (atomic_cas(p, *p, new) != success);
Run Code Online (Sandbox Code Playgroud)
这显然会使代码不正确.因此,目标是确定是否所有这些指向的对象实际上都需要volatile int.
我一直在研究glibc/nptl的取消点的实现,并将它与POSIX进行比较,除非我弄错了,否则完全错了.使用的基本模型是:
int oldtype = LIBC_ASYNC_CANCEL(); /* switch to asynchronous cancellation mode */
int result = INLINE_SYSCALL(...);
LIBC_CANCEL_RESET(oldtype);
Run Code Online (Sandbox Code Playgroud)
根据POSIX:
在函数调用期间暂停时对取消请求起作用的副作用与单个线程程序中可能在信号中断对函数的调用时看到的副作用相同函数返回[EINTR].任何此类副作用都会在调用任何取消清除处理程序之前发生.
我对这段经文的解读是,如果我打电话open,我可以预期它要么在它无法打开文件之前被取消(连同我的整个线程),要么返回有效的文件描述符或-1和errno值,但从不创建一个新的文件描述符,然后将其丢失到void中.另一方面,取消点的glibc/nptl实现似乎允许竞争条件,其中取消请求恰好在系统调用返回之后但在LIBC_CANCEL_RESET发生之前发生.
我疯了,还是他们的实施真的破了吗?如果是这样,POSIX是否允许这种破坏的行为(除非你手动推迟,这似乎会导致取消完全无法使用),或者他们只是公然忽略了POSIX?
如果这种行为实际上已被破坏,那么在没有这种竞争条件的情况下实施它的正确方法是什么?
在POSIX线程的大多数实现中,在新创建的线程处于能够运行应用程序代码的一致状态之前,需要进行一些初始化.这可能涉及解锁线程结构中的锁,在使用一个的实现中初始化"线程寄存器",初始化线程本地数据(编译器级别的TLS或POSIX线程特定的数据)等.我找不到清楚的保证在线程可以接收任何信号之前完成所有这些初始化; 我能找到的最接近的是2.4.3:
下表定义了一组异步信号安全的函数.因此,应用程序可以无限制地调用信号捕获功能:
...
据推测,这些函数中的一些(至少fork必须检查由pthread_atfork函数建立的全局状态)取决于线程处于一致的初始化状态.
困扰我的一件事是我已经阅读了很多glibc/nptl源代码,并且找不到任何显式同步来防止新创建的线程在完全初始化之前处理信号.我希望线程调用pthread_create在调用之前阻塞所有信号clone,并且一旦初始化完成,新线程就会解除阻塞它们,但是我找不到任何代码,也没有在strace输出中看到它.
例如read,假设应用程序在取消点被阻止,并且接收到信号并调用信号处理程序.Glibc/NPTL通过在系统调用期间启用异步取消来实现取消点,因此据我所知,异步取消将在信号处理程序的整个持续时间内保持有效.这当然是非常错误的,因为有很多函数不是异步取消安全的,但是要求从信号处理程序调用是安全的.
这让我有两个问题:
编辑:我几乎确信自己,任何潜在目标的线程pthread_cancel必须确保永远不能从该线程的上下文中的信号处理程序调用取消点的函数:
一方面,任何可以在可能被取消并且使用任何async-cancel-unsafe函数的线程中调用的信号处理程序必须在调用任何取消点的函数之前禁用取消.这是因为,从信号中断的代码的角度来看,任何这种取消都等同于异步取消.另一方面,信号处理程序无法禁用取消,除非在调用信号处理程序时将运行的代码仅使用异步信号安全函数,因为pthread_setcancelstate它不是异步信号安全的.
我需要在close可能被信号处理程序(有或没有SA_RESTART)中断的情况下调查/测试Linux上某些代码的行为.什么是最方便的设置,使close系统调用睡眠在一个可测量的时间窗口,在此期间,我可以尝试用信号命中过程?一些想法:
但是,由于这些设置有点痛苦,我想知道是否有更多现成的我可以使用它可以提供所需的行为.
GNU C库现在使用DWARF2展开来进行pthread取消,这样C++异常和pthread取消清理处理程序都可以通过公共调用框架展开进程调用,该过程在必要时调用自动对象的析构函数.不过,据我所知,仍然没有标准,规定(POSIX)线程和C++之间的相互作用,可能希望可移植的应用程序应当假定抛出异常出取消清理上下文是一样调用未定义longjmp出其中,取消具有非平凡析构函数的实时自动对象的线程也是未定义的行为.
是否有任何标准化过程正在进行中,以解决这种相互作用,或者是否可以预期未来的未定义?C++ 11在其线程支持中是否有任何类似的POSIX线程消除概念?
如何(在GCC /"GNU C"中)声明一个指向函数的函数指针__attribute__((const))?我的想法是,我希望编译器在可以缓存前一次调用的返回值时,避免生成对通过函数指针调用的函数的多次调用.