我正在尝试使用clone syscall和一个由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,所以通过提高优先级互相排斥会失败,为什么?
答案 0 :(得分:1)
这里有几个问题:
答案 1 :(得分:0)
根据clone()的手册页,堆栈应指向已分配内存中的最后一个地址。您对“stack + STACK_SIZE”的引用实际上超出了已分配的内存。
答案 2 :(得分:0)
clone()
系统调用(特别是CLONE_VM
标志)不适合创建线程的应用程序员直接使用。它是一个低级接口,供图书馆作者创建完整的线程实现。类似地,这些线程的同步原语可以构建在低级futex()
系统调用之上,但同样不适合应用程序员直接使用。
相反,你应该使用pthreads。在pthreads下,使用pthread_create()
代替clone()
; pthread_join()
代替wait()
;并pthread_mutex_lock()
/ pthread_mutex_unlock()
保护关键部分。你的程序的pthreads版本看起来像:
#include <stdio.h>
#include <pthread.h>
#include "error.h"
/*-------------------------------------------------------------------------*/
#define N 100000
int main(int argc, char *argv[])
{
int n = 0;
pthread_mutex_t n_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_t child1, child2;
void *Child(void *args) {
int i, temp;
for (i = 0; i < N; i++) {
pthread_mutex_lock(&n_lock);
temp = n;
temp++;
n = temp;
pthread_mutex_unlock(&n_lock);
}
return 0;
}
printf("initial n = %d\n", n);
if (pthread_create(&child1, NULL, Child, NULL) != 0)
SysError("main:pthread_create");
if (pthread_create(&child2, NULL, Child, NULL) != 0)
SysError("main:pthread_create");
pthread_join(child1, NULL);
pthread_join(child2, NULL);
printf("final n = %d\n", n);
return 0;
}
使用-pthread
标志编译为gcc。
答案 3 :(得分:0)
首先,感谢所有人的指导,见解和想法,我总是向你学习。 作为一项学术活动,我试图通过提高优先级来保证相互排斥,这显然只适用于单处理器。
正如ninjalj所指出的那样,如果“多个SCHED_FIFO进程可以在多个CPU上同时运行”,则代码不起作用
使此代码工作的解决方案只是在一个CPU上运行可执行文件:
... $ taskset -c 0 puerta-clone
效果很好,问候