我很难处理同步问题。 我目前的架构需要像这样:
N个工作流程在共享的内存段上互斥。 当所有人完成工作后,1“屏幕”进程显示共享内存状态
N个进程的工作顺序无关紧要,它们都是相同的,但它们都需要在共享内存上工作ONCE(之后)“屏幕”进程完成了他的工作(因此在相互作用中)也被排除在外。)
我想过组织这样的流程: 我创建了两个信号量,一个用于互斥的二进制(1或0)和一个用作计数器的信号(它的值可以从0到#进程)。
我将使用标准字母表示对信号量的标准操作:
P&P; V是传统的等待和信号Z(sem)=在sem上等待零(仅在sem_counter上使用)
R(sem)=重置sem(仅用于sem_counter)
这是在信号量上运行的公共函数的代码:
int P(int semid, int semnum) // signal
{
struct sembuf cmd;
cmd.sem_num = semnum;
cmd.sem_op = -1;
cmd.sem_flg = 0;
semop(semid, &cmd, 1);
return 1;
}
int V(int semid, int semnum) // wait
{
struct sembuf cmd;
cmd.sem_num = semnum;
cmd.sem_op = 1;
cmd.sem_flg = 0;
semop(semid, &cmd, 1);
return 0;
}
int Z(int semid, int semnum) // wait for zero
{
struct sembuf cmd;
cmd.sem_num = semnum;
cmd.sem_op = 0;
cmd.sem_flg = 0;
if(semop(semid, &cmd, 1) < 0)
{
fprintf (stderr, "Errore inizializzazione del semaforo\n%s\n",
strerror(errno) );
}
return 0;
}
int R(int semid, int semnum, int val) // reset
{
union semun arg;
arg.val = val;
if( semctl(semid,semnum,SETVAL,arg) == -1 )
{
fprintf (stderr, "Errore inizializzazione del semaforo\n%s\n",
strerror(errno) );
}
}
这是重置计数器信号量的“显示”过程的代码:
while( 1 )
{
printf("Initialization \n");
// signal ME semaphore
inuso = P(sem_id,0);
printf("Doing work on the shared memory \n");
// reset counter semaphore
R(sem_id_counter,0,N_PROC_DEFAULT);
printf("Again doing work on the shared memory \n");
// release ME semaphore
inuso = V(sem_id,0);
// wait for sem counter to become 0
Z(sem_id_counter,0);
}
这是减少反信号量的工作过程的代码:
while(1)
{
// try to diminish counter semaphore
P(sem_id_counter,0);
// asks for ME semaphore
inuso=P(sem_id,0);
printf("Doing stuff on the shared memory");
// releases ME semaphore
inuso=V(sem_id,0);
// waits for other processes to finish (4 sem_counter 2 become 0)
Z(sem_id_counter,0);
}
问题是他们最终会被困住;如果我从“工作过程”中删除Z(即我不会让他们在再次尝试之前等待其他人),就不会发生这种情况。
答案 0 :(得分:2)
问题在于它们最终会卡住
考虑这一事件:
P(sem_id_counter,0);
返回,使得计数器信号量的值为零。现在&#34;显示&#34;进程已准备好运行并立即执行从
返回Z(sem_id_counter,0);
以及
printf("Initialization \n");
inuso = P(sem_id,0);
在工作流程执行P(sem_id,0);
之前阻止工作流程,直到计数器信号量重置为N_PROC_DEFAULT
,比如 5 。
Z()
,其他正在等待的工作流程将计数器信号量减少到不小于 1 。 {1}} 实际上,只要计数器信号量可以重置为P(sem_id_counter,0);
而没有每个工作进程等待或已经等待零计数,就会发生类似的死锁。确保不会发生这种情况的一种方法是测试(在#34;显示&#34;流程循环的开始)等待增加 semval 的进程数量N_PROC_DEFAULT
,仅在该号码为P(sem_id_counter,0)
之后继续:
N_PROC_DEFAULT
或者,如果您不想轮询工作人员,可以使 // wait until all workers are waiting in P(sem_id_counter,0)
struct timespec req = { 0, 100000000 }; // 0.1 s
while (semctl(sem_id_counter, 0, GETNCNT) < N_PROC_DEFAULT)
nanosleep(&req, NULL);
printf("Initialization \n");
…
包含2个信号量的数组,并使用额外的计数信号量来表示工作人员等待 0 在主要柜台上,i。即
sem_id_counter
中的将两个计数器设置为R()
( cmd N_PROC_DEFAULT
)
在&#34;显示&#34;结束时流程循环执行SETALL
而不是Z(sem_id_counter, 1)
在工作流程循环结束时执行Z(…, 0)
。