C共享内存整数没有得到更新
C shared memory integer doesn't get updated
我正在用 C 实现 reader-writers 问题。如您所见,我 fork 了 2 次,每次都会生成一个 reader 或 writer 并等待一些时间。我还使用两个信号量满足了线程安全性。首先是保护 rcount 的 mutex
,其次是保护互斥的 writeblock
。问题是我的计数器值没有改变,尽管我已经将它用作共享内存。
代码:
#include <stdio.h>
#include <semaphore.h>
#include <sys/ipc.h>
#include <sys/shm.h>
sem_t mutex,writeblock;
int data = 0,rcount = 0,shmid;
void reader()
{
sem_wait(&mutex);
rcount = rcount + 1;
if(rcount==1)
sem_wait(&writeblock);
int *counter=shmat(shmid,NULL,0);
printf("im a reader and counter is %d \n\n",*counter);
shmdt(counter);
sem_post(&mutex);
sleep(1);
sem_wait(&mutex);
rcount = rcount - 1;
if(rcount==0)
sem_post(&writeblock);
sem_post(&mutex);
}
void writer()
{
sem_wait(&writeblock);
int status=0;
int *counter=shmat(shmid,NULL,0);
*counter++;
printf("im a writer and I incremented the counter and after that the counter is %d \n\n",*counter);
shmdt(counter);
sleep(1);
sem_post(&writeblock);
}
int main()
{
int i,b;
sem_init(&mutex,0,1);
sem_init(&writeblock,0,1);
shmid = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0666);
if (shmid <0)
printf("shmget err");
if(fork()==0)
{
for (i=0;i<2;i++)
{
if(fork()==0)
{
sleep(i);
writer();
}
}
}
else
{
for (i=0;i<2;i++)
{
if(fork()==0)
{
sleep(i*2);
reader();
}
}
}
}
错误终端:
$ im a reader and counter is 0
im a writer and I incremented the counter and after that the counter is 0
im a writer and I incremented the counter and after that the counter is 0
im a reader and counter is 0
im a writer and I incremented the counter and after that the counter is 0
im a reader and counter is 0
*counter++
递增计数器,而不是计数器指向的内容。 (*counter)++
递增计数器指向的内容。
正如另一个答案中已经指出的那样,表达式 *counter++
是错误的。由于rules of operator precedence,所以一定是(*counter)++
.
但是,即使修复了该错误,您的程序仍无法按预期运行,原因如下:
在您的问题中,您使用以下语句描述了程序的预期行为:
As you can see I fork 2 times and each time will generate a reader or writer with some amount of waiting.
你的这种说法是不正确的。你实际上 fork 了 7 次,也就是说你有 8 个进程。其中 3 个进程将调用 writer
函数,3 个将调用 reader
函数。
在第一个for
循环中,在循环的第一次迭代中fork出来的子进程会正常调用writer
函数,但之后就不会跳出环形。相反,它将执行循环的第二次迭代。这意味着您有两个进程执行循环的第二次迭代。
由于这可能不是故意的,我建议您将第一个 for
循环更改为以下内容:
for (i=0;i<2;i++)
{
if(fork()==0)
{
sleep(i);
writer();
break; //breaks out of "for" loop
}
}
你的第二个 for
循环(else
块内的循环)有同样的问题。
修复两个循环后,您现在只会分叉 5 次,因此总共有 6 个进程。这可能是你想要的。第一个进程创建了两个写入进程,还创建了一个创建两个 reader 进程的进程。
但是,您的程序的另一个问题是每个进程都有自己的 rcount
变量副本。因此,您必须对该变量执行与 counter
变量相同的操作(即使用共享内存)。
另外,您调用函数 sem_init
时参数 pshared
设置为零。根据 documentation of this function,只有在同一进程的线程之间共享信号量时才应该这样做。但是,使用 fork
,您正在创建单独的进程。因此,您应该将此参数设置为非零值。
我正在用 C 实现 reader-writers 问题。如您所见,我 fork 了 2 次,每次都会生成一个 reader 或 writer 并等待一些时间。我还使用两个信号量满足了线程安全性。首先是保护 rcount 的 mutex
,其次是保护互斥的 writeblock
。问题是我的计数器值没有改变,尽管我已经将它用作共享内存。
代码:
#include <stdio.h>
#include <semaphore.h>
#include <sys/ipc.h>
#include <sys/shm.h>
sem_t mutex,writeblock;
int data = 0,rcount = 0,shmid;
void reader()
{
sem_wait(&mutex);
rcount = rcount + 1;
if(rcount==1)
sem_wait(&writeblock);
int *counter=shmat(shmid,NULL,0);
printf("im a reader and counter is %d \n\n",*counter);
shmdt(counter);
sem_post(&mutex);
sleep(1);
sem_wait(&mutex);
rcount = rcount - 1;
if(rcount==0)
sem_post(&writeblock);
sem_post(&mutex);
}
void writer()
{
sem_wait(&writeblock);
int status=0;
int *counter=shmat(shmid,NULL,0);
*counter++;
printf("im a writer and I incremented the counter and after that the counter is %d \n\n",*counter);
shmdt(counter);
sleep(1);
sem_post(&writeblock);
}
int main()
{
int i,b;
sem_init(&mutex,0,1);
sem_init(&writeblock,0,1);
shmid = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0666);
if (shmid <0)
printf("shmget err");
if(fork()==0)
{
for (i=0;i<2;i++)
{
if(fork()==0)
{
sleep(i);
writer();
}
}
}
else
{
for (i=0;i<2;i++)
{
if(fork()==0)
{
sleep(i*2);
reader();
}
}
}
}
错误终端:
$ im a reader and counter is 0
im a writer and I incremented the counter and after that the counter is 0
im a writer and I incremented the counter and after that the counter is 0
im a reader and counter is 0
im a writer and I incremented the counter and after that the counter is 0
im a reader and counter is 0
*counter++
递增计数器,而不是计数器指向的内容。 (*counter)++
递增计数器指向的内容。
正如另一个答案中已经指出的那样,表达式 *counter++
是错误的。由于rules of operator precedence,所以一定是(*counter)++
.
但是,即使修复了该错误,您的程序仍无法按预期运行,原因如下:
在您的问题中,您使用以下语句描述了程序的预期行为:
As you can see I fork 2 times and each time will generate a reader or writer with some amount of waiting.
你的这种说法是不正确的。你实际上 fork 了 7 次,也就是说你有 8 个进程。其中 3 个进程将调用 writer
函数,3 个将调用 reader
函数。
在第一个for
循环中,在循环的第一次迭代中fork出来的子进程会正常调用writer
函数,但之后就不会跳出环形。相反,它将执行循环的第二次迭代。这意味着您有两个进程执行循环的第二次迭代。
由于这可能不是故意的,我建议您将第一个 for
循环更改为以下内容:
for (i=0;i<2;i++)
{
if(fork()==0)
{
sleep(i);
writer();
break; //breaks out of "for" loop
}
}
你的第二个 for
循环(else
块内的循环)有同样的问题。
修复两个循环后,您现在只会分叉 5 次,因此总共有 6 个进程。这可能是你想要的。第一个进程创建了两个写入进程,还创建了一个创建两个 reader 进程的进程。
但是,您的程序的另一个问题是每个进程都有自己的 rcount
变量副本。因此,您必须对该变量执行与 counter
变量相同的操作(即使用共享内存)。
另外,您调用函数 sem_init
时参数 pshared
设置为零。根据 documentation of this function,只有在同一进程的线程之间共享信号量时才应该这样做。但是,使用 fork
,您正在创建单独的进程。因此,您应该将此参数设置为非零值。