克隆系统调用和互斥
我正在尝试使用克隆系统调用和一个由 2 个线程共享的递增计数器的小示例进行练习。代码如下:
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <sched.h>
#include "error.h"
/*------------------------- Mutual exclusion ------------------------------*/
void EnterCZ()
{
if (sched_setscheduler(getpid(), SCHED_FIFO, &(struct sched_param) { .sched_priority = 1 }) == -1)
SysError("EntrarZC:sched_setscheduler");
}
void ExitCZ()
{
if (sched_setscheduler(getpid(), SCHED_OTHER, &(struct sched_param) { .sched_priority = 0 }) == -1)
SysError("SalirZC:sched_setscheduler");
}
/*-------------------------------------------------------------------------*/
#define STACK_SIZE 65536
#define N 100000
int main(int argc, char *argv[])
{
int n = 0;
char *stack;
int Child(void *args) {
int i, temp;
for (i = 0; i < N; i++) {
EnterCZ();
temp = n;
temp++;
n = temp;
ExitCZ();
}
return 0;
}
printf("initial n = %d\n", n);
if ((stack = malloc(STACK_SIZE)) == NULL)
RTError("main:malloc");
if (clone(Child, stack + STACK_SIZE, SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM, NULL) == -1)
SysError("main:clone");
if ((stack = malloc(STACK_SIZE)) == NULL)
RTError("main:malloc");
if (clone(Child, stack + STACK_SIZE, SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM, NULL) == -1)
SysError("main:clone");
while (wait(NULL) != -1) ;
printf("final n = %d\n", n);
return 0;
}
执行结果为:
initial n = 0
final n = 199999
应该是200000,所以通过提高优先级的方式进行互斥失败,为什么?
I'm trying to practice with clone syscall and a little example of an incrementing counter shared by 2 threads. Code is as follows:
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <sched.h>
#include "error.h"
/*------------------------- Mutual exclusion ------------------------------*/
void EnterCZ()
{
if (sched_setscheduler(getpid(), SCHED_FIFO, &(struct sched_param) { .sched_priority = 1 }) == -1)
SysError("EntrarZC:sched_setscheduler");
}
void ExitCZ()
{
if (sched_setscheduler(getpid(), SCHED_OTHER, &(struct sched_param) { .sched_priority = 0 }) == -1)
SysError("SalirZC:sched_setscheduler");
}
/*-------------------------------------------------------------------------*/
#define STACK_SIZE 65536
#define N 100000
int main(int argc, char *argv[])
{
int n = 0;
char *stack;
int Child(void *args) {
int i, temp;
for (i = 0; i < N; i++) {
EnterCZ();
temp = n;
temp++;
n = temp;
ExitCZ();
}
return 0;
}
printf("initial n = %d\n", n);
if ((stack = malloc(STACK_SIZE)) == NULL)
RTError("main:malloc");
if (clone(Child, stack + STACK_SIZE, SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM, NULL) == -1)
SysError("main:clone");
if ((stack = malloc(STACK_SIZE)) == NULL)
RTError("main:malloc");
if (clone(Child, stack + STACK_SIZE, SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM, NULL) == -1)
SysError("main:clone");
while (wait(NULL) != -1) ;
printf("final n = %d\n", n);
return 0;
}
execution result is:
initial n = 0
final n = 199999
should be 200000, so mutual exclusion by means of raising priority fails, why?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这里有几个问题:
There are several things wrong here:
根据clone()的手册页,堆栈应指向分配的内存中的最后一个地址。您对“stack + STACK_SIZE”的引用实际上超出了分配的内存。
According to the man page for clone(), the stack should point to the last address in allocated memory. Your reference of "stack + STACK_SIZE" is actually beyond the allocated memory.
clone()
系统调用(特别是CLONE_VM
标志)不适合由创建线程的应用程序程序员直接使用。它是一个低级接口,旨在供库作者创建完整的线程实现。类似地,这些线程的同步原语可以构建在低级 futex() 系统调用之上,但这同样不适合应用程序程序员直接使用。相反,您应该使用 pthreads。在pthreads下,使用
pthread_create()
而不是clone()
;pthread_join()
而不是wait()
;和pthread_mutex_lock()
/pthread_mutex_unlock()
来保护关键部分。程序的 pthreads 版本如下所示:使用
-pthread
标志编译到 gcc。The
clone()
syscall (particularly theCLONE_VM
flag) is not intended for direct use by application programmers creating threads. It is a low-level interface, intended for library authors creating full threading implementations. Similarly, sychronisation primitives for these threads can be built on top of the low-levelfutex()
system call, but again this is not intended for direct use by application programmers.Instead, you should be using pthreads. Under pthreads, use
pthread_create()
instead ofclone()
;pthread_join()
instead ofwait()
; andpthread_mutex_lock()
/pthread_mutex_unlock()
to protect critical sections. The pthreads version of your program would look like:Compile with the
-pthread
flag to gcc.首先,感谢大家的指点、见解和想法,我总是向你们学习。
作为一项学术练习,我试图通过提高优先级来保证互斥,显然,这仅适用于单处理器。
正如 ninjalj 指出的那样,如果“多个 SCHED_FIFO 进程可以在多个 CPU 上同时运行”,则该代码将无法工作。
使该代码工作的解决方案就是仅在一个 CPU 上运行可执行文件:
...$taskset -c 0 puerta-clone
效果很好,问候
First of all, thanks to everybody for pointers, insights and ideas, I always learn from you.
As an academic exercise, I was trying to guarantee mutual exclusion by rising priorities, which, obviously, only works for uniprocessors.
As ninjalj pointed out the code doesn't work if "Several SCHED_FIFO processes can run simultaneously on several CPUs"
The solution to make this code work is simply to run executable on only one CPU:
...$ taskset -c 0 puerta-clone
works well, regards