我和一位同事一起,负责使用信号量同步一个"手写"的C程序。 任务是在 int[4] 字段循环中移动1
,其他条目0
。
#include "workers.h"
#include "semaphores.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
//-----------------------------------------------------------------------------
// global variables (all volatile!)
//-----------------------------------------------------------------------------
#define SIZE 4
volatile int ring[4];
volatile int von_position;
volatile int nach_position;
volatile semaphore semaphoren[4];
//-----------------------------------------------------------------------------
// call text_setup() once before starting the test
//-----------------------------------------------------------------------------
void test_setup(void) {
printf("Test Setupn");
for(int i= 0; i<4; i++){
semaphoren[i] = sem_init(1);
}
von_position = 0;
nach_position = 1;
readers=0; // maximal 1 (nicht veraendern!)
writers=4; // maximal 19
}
//-----------------------------------------------------------------------------
// test_end() is called after all workers have finished
//-----------------------------------------------------------------------------
void test_end(void) {
for(int i = 0; i<4; i++){
printf("%i ", ring[i]);
}
}
//-----------------------------------------------------------------------------
// those 4 workers execute in parallel
//-----------------------------------------------------------------------------
void writer(long my_id) {
for(int i =0; i<500; i++){
sem_p(semaphoren[my_id]);
printf("Writer %i :, %i>%i n",(int) my_id, von_position, nach_position); // ***
ring[von_position] = 0;
ring[nach_position] = 1;
sem_v(semaphoren[my_id]);
if(von_position == 3){von_position = 0;}
else von_position ++;
if(nach_position == 3) {nach_position = 0;}
else nach_position ++;
}
}
void reader(long my_id) {
}
这是从提供给我们的旧环形缓冲区程序派生出来的。它使用 4 个"编写器"进程。
问题是,完成后,数组中总是只有一个,但是在大约 10 次运行中,在 500 次运行中,我们得到了 printf()(代码中的***
)的中间输出,就像 3 > 0
一样,在下一行0 < 2
左右。
到目前为止,尝试了很多,但没有成功。
希望我能得到一些好提示
示例代码不会"移动"1,而只是存储0和1。我的猜测是线程应该以同步的方式移动元素。线程 0 从环 [0] 移动到环 [1],线程 1 从环 [1] 移动到环[2],...线程 3 从环[3] 移动到环 [0]。线程可以并行读取和全部写入,但需要同步以防止读取和写入之间的冲突。使用 4 个信号量似乎是实现这一点的简单方法。
读取和写入共享的非原子变量。因此,它表现出竞争条件,并且其行为未根据 C 标准定义。假设您将volatile
更改为_Atomic
,并将所有加载/存储交换到原子变量与atomic_load_explicit(x, memory_order_seq_cst)/atomic_store_explicit(x, memory_order_seq_cst)
,您的
void writer(long my_id)
{
for(int i =0; i<500; i++)
{
sem_p(semaphoren[my_id]);
printf("Writer %i :, %i>%i n",(int) my_id, von_position, nach_position);
ring[von_position] = 0;
ring[nach_position] = 1;
sem_v(semaphoren[my_id]);
if(von_position == 3){von_position = 0;}
else von_position ++;
if(nach_position == 3) {nach_position = 0;}
else nach_position ++;
}
}
仍然可以在sem_v()
和第一个if()
之间,在if()
和else
之间中断,等等。特别是,第一个writer()
可以在递增von_position
(模4)之后和递增nach_position
之前中断。因此,下一个编写器将看到von_position == nach_position
,如果该编写器在同一个位置被打断,则下一个编写器将看到von_position > nach_position
,依此类推。
实际上,您应该将sem_v()
移动到循环的末尾。