如何初始化信号量数组并使用它?
How to initialize an array of semaphore and use it?
我想创建一个包含 5 个信号量的数组,这样只有第一个信号量值的值为 1 {1,0,0,0,0}。但是,当我 运行 代码时,它给了我段错误。我是否正确初始化并正确使用了它?基本上,由于第一个信号量的值为 1,因此第一个 child 不会被阻塞,在第一个 child 成功执行后,它将向第二个 child 发出信号以执行,等等
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <semaphore.h>
#define NUM_PROCESSES 5
int main()
{
int i, j, pid;
int shmid;
sem_t *sem[5];
shmid = shmget(IPC_PRIVATE, sizeof(sem_t) * 5 , IPC_CREAT | 0600);
*sem = (sem_t *)shmat(shmid, NULL, 0);
sem_init(sem[0], 1, 1);
for (int k = 1; k < NUM_PROCESSES; k++)
{
sem_init(sem[k], 1, 0);
}
for (i = 0; i < NUM_PROCESSES; i++)
{
if ((pid = fork()) == 0)
{
break;
}
}
if (pid == 0)
{
sem_wait(sem[i]);
printf("I am child %d\n", i);
for (j = i * 10; j < i * 10 + 10; j++)
{
printf("%d ", j);
fflush(stdout);
usleep(250000);
}
printf("\n\n");
sem_post(sem[i + 1]);
shm_destroy(sem[i]);
}
else
{
for (i = 0; i < NUM_PROCESSES; i++)
{
wait(NULL);
}
shmctl(shmid, IPC_RMID, 0);
}
}
第二次编辑:使用不带指针的 sem,现在我的问题是在打印第一个 child 之后,程序挂起(非终止且不打印任何内容)。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <semaphore.h>
#define NUM_PROCESSES 5
int main()
{
int i, j, pid;
int shmid;
sem_t sem[5];
sem_init(&sem[0], 1, 1);
for (int k = 1; k < NUM_PROCESSES; k++)
{
sem_init(&sem[k], 1, 0);
}
for (i = 0; i < NUM_PROCESSES; i++)
{
if ((pid = fork()) == 0)
{
break;
}
}
if (pid == 0)
{
sem_wait(&sem[i]);
printf("I am child %d\n", i);
for (j = i * 10; j < i * 10 + 10; j++)
{
printf("%d ", j);
fflush(stdout);
usleep(250000);
}
printf("\n\n");
if (i + 1 < NUM_PROCESSES)
{
sem_post(&sem[i + 1]);
}
}
else
{
for (i = 0; i < NUM_PROCESSES; i++)
{
wait(NULL);
}
}
}
第三个版本:使用共享内存区域但 运行 再次陷入段错误。我不明白现在是怎么回事。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <semaphore.h>
#define NUM_PROCESSES 5
int main()
{
int i, j, pid;
int shmid;
sem_t *sem[NUM_PROCESSES];
shmid = shmget(IPC_PRIVATE, sizeof(sem_t) * NUM_PROCESSES, IPC_CREAT | 0600);
*sem = (sem_t *)shmat(shmid, NULL, 0);
sem_init(sem[0], 1, 1);
for (int k = 1; k < NUM_PROCESSES; k++)
{
sem_init(sem[k], 1, 0);
}
for (i = 0; i < NUM_PROCESSES; i++)
{
if ((pid = fork()) == 0)
{
break;
}
}
if (pid == 0)
{
if (sem_post(sem[i + 1]) != -1)
{
printf("hello");
}
sem_wait(sem[i]);
printf("I am child %d\n", i);
for (j = i * 10; j < i * 10 + 10; j++)
{
printf("%d ", j);
fflush(stdout);
usleep(250000);
}
printf("\n\n");
if (i + 1 < NUM_PROCESSES)
{
sem_post(sem[i + 1]);
}
}
else
{
for (i = 0; i < NUM_PROCESSES; i++)
{
wait(NULL);
}
}
}
堆栈上的 sem_t
数组(如 OP 的第二次尝试)不适合 inter-process 通信,因为信号量的当前状态将被 fork()
并且子进程将对它们自己的信号量副本进行操作。因此 sem_t
的数组应该在共享内存段内初始化(如 OP 的第一次尝试)。在对 fork()
的调用中,子进程继承了父进程附加的共享内存段,因此所有子进程将在该内存段中使用相同的信号量。
OP 第一次尝试中的代码不正确。它正在分配正确数量的内存,但将内存视为数组
sem_t *
而不是 sem_t
的数组。它正在将指向共享内存段的指针分配给数组的第一个元素,但正在使用数组的其他元素而不对其进行初始化。
那些数字 5
应该用宏 NUM_PROCESSES
替换以保持一致性。此外,不需要将 shmat
调用的 return 值显式转换为 sem_t *
,因为将 void *
转换为另一种对象类型不需要显式转换。
旧代码:
sem_t *sem[5];
shmid = shmget(IPC_PRIVATE, sizeof(sem_t) * 5 , IPC_CREAT | 0600);
*sem = (sem_t *)shmat(shmid, NULL, 0);
sem_init(sem[0], 1, 1);
for (int k = 1; k < NUM_PROCESSES; k++)
{
sem_init(sem[k], 1, 0);
}
更正后的代码:
sem_t *sem;
shmid = shmget(IPC_PRIVATE, sizeof(sem_t) * NUM_PROCESSES, IPC_CREAT | 0600);
sem = shmat(shmid, NULL, 0);
sem_init(&sem[0], 1, 1);
for (int k = 1; k < NUM_PROCESSES; k++)
{
sem_init(&sem[k], 1, 0);
}
在下一个信号量上调用 sem_post
的子项中的原始代码需要检查 是 下一个信号量:
旧代码:
sem_post(sem[i + 1]);
更正后的代码:
if (i + 1 < NUM_PROCESSES)
{
sem_post(&sem[i + 1]);
}
原码中子有调用shm_destroy(sem[i]);
。这不是标准的 POSIX 函数。我猜 OP 的意思是调用 sem_destroy(sem[i]);
。通过之前的更正,现在应该是 sem_destroy(&sem[i]);
.
旧代码:
shm_destroy(sem[i]);
更正后的代码:
sem_destroy(&sem[i]);
综合起来:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <semaphore.h>
#define NUM_PROCESSES 5
int main(void)
{
int i, j;
pid_t pid;
int shmid;
sem_t *sem;
shmid = shmget(IPC_PRIVATE, sizeof(sem_t) * NUM_PROCESSES, IPC_CREAT | 0600);
sem = shmat(shmid, NULL, 0);
sem_init(&sem[0], 1, 1);
for (int k = 1; k < NUM_PROCESSES; k++)
{
sem_init(&sem[k], 1, 0);
}
for (i = 0; i < NUM_PROCESSES; i++)
{
if ((pid = fork()) == 0)
{
break;
}
}
if (pid == 0)
{
sem_wait(&sem[i]);
printf("I am child %d\n", i);
for (j = i * 10; j < i * 10 + 10; j++)
{
printf("%d ", j);
fflush(stdout);
usleep(250000);
}
printf("\n\n");
if (i + 1 < NUM_PROCESSES)
{
sem_post(&sem[i + 1]);
}
sem_destroy(&sem[i]);
}
else
{
for (i = 0; i < NUM_PROCESSES; i++)
{
wait(NULL);
}
shmctl(shmid, IPC_RMID, 0);
}
}
我想创建一个包含 5 个信号量的数组,这样只有第一个信号量值的值为 1 {1,0,0,0,0}。但是,当我 运行 代码时,它给了我段错误。我是否正确初始化并正确使用了它?基本上,由于第一个信号量的值为 1,因此第一个 child 不会被阻塞,在第一个 child 成功执行后,它将向第二个 child 发出信号以执行,等等
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <semaphore.h>
#define NUM_PROCESSES 5
int main()
{
int i, j, pid;
int shmid;
sem_t *sem[5];
shmid = shmget(IPC_PRIVATE, sizeof(sem_t) * 5 , IPC_CREAT | 0600);
*sem = (sem_t *)shmat(shmid, NULL, 0);
sem_init(sem[0], 1, 1);
for (int k = 1; k < NUM_PROCESSES; k++)
{
sem_init(sem[k], 1, 0);
}
for (i = 0; i < NUM_PROCESSES; i++)
{
if ((pid = fork()) == 0)
{
break;
}
}
if (pid == 0)
{
sem_wait(sem[i]);
printf("I am child %d\n", i);
for (j = i * 10; j < i * 10 + 10; j++)
{
printf("%d ", j);
fflush(stdout);
usleep(250000);
}
printf("\n\n");
sem_post(sem[i + 1]);
shm_destroy(sem[i]);
}
else
{
for (i = 0; i < NUM_PROCESSES; i++)
{
wait(NULL);
}
shmctl(shmid, IPC_RMID, 0);
}
}
第二次编辑:使用不带指针的 sem,现在我的问题是在打印第一个 child 之后,程序挂起(非终止且不打印任何内容)。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <semaphore.h>
#define NUM_PROCESSES 5
int main()
{
int i, j, pid;
int shmid;
sem_t sem[5];
sem_init(&sem[0], 1, 1);
for (int k = 1; k < NUM_PROCESSES; k++)
{
sem_init(&sem[k], 1, 0);
}
for (i = 0; i < NUM_PROCESSES; i++)
{
if ((pid = fork()) == 0)
{
break;
}
}
if (pid == 0)
{
sem_wait(&sem[i]);
printf("I am child %d\n", i);
for (j = i * 10; j < i * 10 + 10; j++)
{
printf("%d ", j);
fflush(stdout);
usleep(250000);
}
printf("\n\n");
if (i + 1 < NUM_PROCESSES)
{
sem_post(&sem[i + 1]);
}
}
else
{
for (i = 0; i < NUM_PROCESSES; i++)
{
wait(NULL);
}
}
}
第三个版本:使用共享内存区域但 运行 再次陷入段错误。我不明白现在是怎么回事。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <semaphore.h>
#define NUM_PROCESSES 5
int main()
{
int i, j, pid;
int shmid;
sem_t *sem[NUM_PROCESSES];
shmid = shmget(IPC_PRIVATE, sizeof(sem_t) * NUM_PROCESSES, IPC_CREAT | 0600);
*sem = (sem_t *)shmat(shmid, NULL, 0);
sem_init(sem[0], 1, 1);
for (int k = 1; k < NUM_PROCESSES; k++)
{
sem_init(sem[k], 1, 0);
}
for (i = 0; i < NUM_PROCESSES; i++)
{
if ((pid = fork()) == 0)
{
break;
}
}
if (pid == 0)
{
if (sem_post(sem[i + 1]) != -1)
{
printf("hello");
}
sem_wait(sem[i]);
printf("I am child %d\n", i);
for (j = i * 10; j < i * 10 + 10; j++)
{
printf("%d ", j);
fflush(stdout);
usleep(250000);
}
printf("\n\n");
if (i + 1 < NUM_PROCESSES)
{
sem_post(sem[i + 1]);
}
}
else
{
for (i = 0; i < NUM_PROCESSES; i++)
{
wait(NULL);
}
}
}
堆栈上的 sem_t
数组(如 OP 的第二次尝试)不适合 inter-process 通信,因为信号量的当前状态将被 fork()
并且子进程将对它们自己的信号量副本进行操作。因此 sem_t
的数组应该在共享内存段内初始化(如 OP 的第一次尝试)。在对 fork()
的调用中,子进程继承了父进程附加的共享内存段,因此所有子进程将在该内存段中使用相同的信号量。
OP 第一次尝试中的代码不正确。它正在分配正确数量的内存,但将内存视为数组
sem_t *
而不是 sem_t
的数组。它正在将指向共享内存段的指针分配给数组的第一个元素,但正在使用数组的其他元素而不对其进行初始化。
那些数字 5
应该用宏 NUM_PROCESSES
替换以保持一致性。此外,不需要将 shmat
调用的 return 值显式转换为 sem_t *
,因为将 void *
转换为另一种对象类型不需要显式转换。
旧代码:
sem_t *sem[5];
shmid = shmget(IPC_PRIVATE, sizeof(sem_t) * 5 , IPC_CREAT | 0600);
*sem = (sem_t *)shmat(shmid, NULL, 0);
sem_init(sem[0], 1, 1);
for (int k = 1; k < NUM_PROCESSES; k++)
{
sem_init(sem[k], 1, 0);
}
更正后的代码:
sem_t *sem;
shmid = shmget(IPC_PRIVATE, sizeof(sem_t) * NUM_PROCESSES, IPC_CREAT | 0600);
sem = shmat(shmid, NULL, 0);
sem_init(&sem[0], 1, 1);
for (int k = 1; k < NUM_PROCESSES; k++)
{
sem_init(&sem[k], 1, 0);
}
在下一个信号量上调用 sem_post
的子项中的原始代码需要检查 是 下一个信号量:
旧代码:
sem_post(sem[i + 1]);
更正后的代码:
if (i + 1 < NUM_PROCESSES)
{
sem_post(&sem[i + 1]);
}
原码中子有调用shm_destroy(sem[i]);
。这不是标准的 POSIX 函数。我猜 OP 的意思是调用 sem_destroy(sem[i]);
。通过之前的更正,现在应该是 sem_destroy(&sem[i]);
.
旧代码:
shm_destroy(sem[i]);
更正后的代码:
sem_destroy(&sem[i]);
综合起来:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <semaphore.h>
#define NUM_PROCESSES 5
int main(void)
{
int i, j;
pid_t pid;
int shmid;
sem_t *sem;
shmid = shmget(IPC_PRIVATE, sizeof(sem_t) * NUM_PROCESSES, IPC_CREAT | 0600);
sem = shmat(shmid, NULL, 0);
sem_init(&sem[0], 1, 1);
for (int k = 1; k < NUM_PROCESSES; k++)
{
sem_init(&sem[k], 1, 0);
}
for (i = 0; i < NUM_PROCESSES; i++)
{
if ((pid = fork()) == 0)
{
break;
}
}
if (pid == 0)
{
sem_wait(&sem[i]);
printf("I am child %d\n", i);
for (j = i * 10; j < i * 10 + 10; j++)
{
printf("%d ", j);
fflush(stdout);
usleep(250000);
}
printf("\n\n");
if (i + 1 < NUM_PROCESSES)
{
sem_post(&sem[i + 1]);
}
sem_destroy(&sem[i]);
}
else
{
for (i = 0; i < NUM_PROCESSES; i++)
{
wait(NULL);
}
shmctl(shmid, IPC_RMID, 0);
}
}