进程似乎不会减少信号量
Processes does not seem to decrement semaphore
我的 c 程序有问题。
我已经在这里写了一个关于同一个程序的主题(我有 fork 的问题):
我正在模拟 F1 练习。现在分叉,我得到了一些不相关的数据(1/3 的汽车时间错误(0min0s0ms)。
我认为这是一个并发问题,所以我尝试 实现一个信号量 。
这样做的目的是一次只允许 1 个进程写入共享内存。
但是现在,我所有的输出数据都是错误的
例如:
- 大多数飞行员号码不正确(很多 n°0)。
- 他们都有不切实际的最佳时间 (0min 0sec 0ms)。
我注意到的一件事是,如果我删除增加信号量 1 (sem + 1) 的 sem 操作,在写入共享内存之前没有进程被阻塞但是他们应该因为信号量永远不会递增(它只是还在递减).
这是 "make the race":
的程序
/* /!\ COMPILER AVEC -lm && -lpthread /!\ */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sem.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <wait.h>
#include "CourseF1.h"
#include "ResultCourse.h"
#define MAX_PILOTES 22
#define MAX_TOURS 44
int semid;
float ranf() { // PRNG for floats [0, 1].
float r = rand() / (float) RAND_MAX;
return r;
}
/**
*
* method based on Box-Muller transformation: https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
*
**/
float randGaussien(float m, float s) { /* median m, standard deviation s */
float x1, x2, w, y1, result;
float y2;
int use_last = 0;
if (use_last) /* use value of last call */
{
y1 = y2;
use_last = 0;
}
else
{
do {
x1 = 2.0 * ranf() - 1.0;
x2 = 2.0 * ranf() - 1.0;
w = x1 * x1 + x2 * x2;
} while ( w >= 1.0 );
w = sqrt( (-2.0 * log( w ) ) / w );
y1 = x1 * w;
y2 = x2 * w;
use_last = 1;
}
result = ( m + y1 * s );
if (result < 0) {
return 0.0;
}
return result;
}
int genTime(const int min, const int max) {
return ((rand() % (max-min + 1)) + min); // Generate a random number between min and max
}
int genRaceEvents(const int max) { // Decide about race events
return rand() % max; // Generate a number between 0 and max - 1
}
int compareBest(const void *p1, const void *p2) { // Compare the best times
const struct Pilote *elem1 = p1;
const struct Pilote *elem2 = p2;
if (elem1->best < elem2->best) return -1;
if (elem1->best > elem2->best) return 1;
return 0;
}
int compareTot(const void *p1, const void *p2) { // Compare the total times
const struct Pilote *elem1 = p1;
const struct Pilote *elem2 = p2;
if (elem1->totalTime < elem2->totalTime) return -1;
if (elem1->totalTime > elem2->totalTime) return 1;
return 0;
}
void fillTab(struct Pilote tabToFill[], struct Pilote tabFiller[], const int start, const int stop) {
for (int i = start; i < stop; i++) {
tabToFill[i] = tabFiller[i];
}
}
int run(Pilote *p, char* name) {
struct sembuf sem_op; // sembuf struct for semaphore operations
sem_op.sem_num = 0;
sem_op.sem_op = -1; // sem - 1
sem_op.sem_flg = 0;
if (semop(semid, &sem_op, 1) == -1) { // sem operation
perror("Error when decrementing semaphore");
}
/* Instantiation of Pilote struct values */
p->s1 = 3 * 60 * 3600 + 1;
p->bestS1 = 3 * 60 * 3600 + 1;
p->s2 = 3 * 60 * 3600 + 1;
p->bestS2 = 3 * 60 * 3600 + 1;
p->s3 = 3 * 60 * 3600 + 1;
p->bestS3 = 3 * 60 * 3600 + 1;
p->best = 3 * 60 * 3600 + 1;
p->totalTime = 0;
p->isPit = 0;
p->hasGivenUp = 0;
p->hasGivenUpDuringRace = 0;
p->numberOfPits = 0;
for (int i = 0; i < MAX_TOURS; i++) { // For every lap
p->isPit = 0; // At first he doesn't pit
if (!(p->hasGivenUp)) { // If the pilote didn't give up
int givingUpEvent = genRaceEvents(500); // Generate a number between 0 and 499
if (givingUpEvent == 14 && strcmp(name, "Race") == 0) { // If the pilote has given up (during race)
p->best = 3 * 60 * 3600;
p->hasGivenUpDuringRace = 1;
return 0; // Stop le pilote
}
else if (givingUpEvent == 14) { // If the pilote has given up (but not during race)
p->best = 3 * 60 * 3600 + 3;
p->hasGivenUp = 1;
return 0; // Stop the pilote
}
}
if (p->numberOfPits < 2) { // Max 2 stops
p->isPit = genRaceEvents(250); // Generate a number between 0 and 249
if (p->isPit) {
p->numberOfPits++;
if ((strcmp(name, "Practices") == 0)|| (strcmp(name, "Qualifs") == 0)) continue; // Next iteration
}
}
// We do a lap
int S1 = 0.275 * (103000 + randGaussien(5000, 2000)); // Portion of circuit * Gauss curve (min time + fun(median, standard deviation))
int S2 = 0.459 * (103000 + randGaussien(5000, 2000));
int S3 = 0.266 * (103000 + randGaussien(5000, 2000));
if ((strcmp(name, "Race") == 0) && (p->isPit)) { // If we are during race and the pilote pit
S1 += genTime(20 * 3600, 25 * 3600); // We add between 20 and 25sec at Sector 1
}
p->s1 = S1; // Notify time of S1
p->s2 = S2; // Notify time of S2
p->s3 = S3; // etc...
int lap = S1 + S2 + S3;
if (p->bestS1 > S1) p->bestS1 = S1; // If it's its best S1, we modify the best S1
if (p->bestS2 > S2) p->bestS2 = S2; // etc
if (p->bestS3 > S3) p->bestS3 = S3; // etc
if (p->best > lap) p->best = lap; // If it's its best lap time, we modify the best lap time,
if ((strcmp(name, "Race") == 0)) {
p->totalTime += lap; // add the lap time to the total race time
}
} // End of for loop
sem_op.sem_num = 0;
sem_op.sem_op = 1; // sem + 1
sem_op.sem_flg = 0;
if (semop(semid, &sem_op, 1) == -1) { // sem operation
perror("Error when incrementing semaphore");
}
}
int main(int argc, char const *argv[]) {
//srand (time(NULL)); // Useful for random number generation
printf("========================================\n");
for (int i = 0; i < 22; i++) {
printf("Random: %d\n", genRaceEvents(100));
}
printf("=========================================\n");
// Variables for the race
int pilotes_numbers[MAX_PILOTES] = {44, 6, 5, 7, 3, 33, 19, 77, 11, 27, 26, 55, 14, 22, 9, 12, 20, 30, 8, 21, 31, 94}; // Tab containing pilotes numbers
struct Pilote Q2[16]; // Tab of pilotes for Q2
struct Pilote Q3[10]; // Tab of pilotes for Q3
struct Pilote mainRun[MAX_PILOTES]; // Tab of pilotes for other race, practices
struct Pilote *pilotesTab; // pointer to SM
pid_t tabPID[MAX_PILOTES]; // Tab of PID
int shmid = 0; // SM id
key_t key; // Key for SM and Semaphores
/**
* Shared memory
*/
// Key generation for Shared Memory
key = ftok(argv[0], 123); // argv[O] => name of the program launched, ID (char)
// SM initialization
shmid = shmget(key, MAX_PILOTES * sizeof(Pilote), IPC_CREAT | 0644);
if (shmid == -1) {
perror("Erreur when allocating SM.");
return 0;
}
// Attach SM segment
pilotesTab = shmat(shmid, NULL, 0);
/**
* Semaphores
*/
// Semaphores initialization (1 semaphore)
semid = semget(key, 1, IPC_CREAT | 0640); // key, number of semaphores, perm
if(semid == -1) { // Erreur
perror("Error when creating semaphore");
return 0;
}
// Set semaphore value to 1
int rv = semctl(semid, 0, SETVAL, 1); // semid, sem number, operation type, union semun
if (rv == -1) { // sif return value == -1
perror("Error when affecting value to the semaphore");
return 0;
}
/**
* Fork
*/
int j;
for (j = 0; j < MAX_PILOTES; j++) { /* Create 22 processes */
tabPID[j] = fork();
if (tabPID[j] == -1) { // Error
perror("Error when forking\n");
return 0;
}
if (tabPID[j] == 0) { // Child
//
srand(time(NULL) ^ (getpid() << 16));
pilotesTab[j].pilote_id = pilotes_numbers[j]; // Pilote number initialization
run(&pilotesTab[j], "Practices");
exit(0);
}
} /* End of 22 processes */
printf("==================================================== \n");
fillTab(mainRun, pilotesTab, 0, MAX_PILOTES); // Fill the tab before sorting + show to the console
showResults(mainRun, MAX_PILOTES, "Practices");
printf("====================================================\n");
/**
* END TEST
*/
semctl(semid, 0, IPC_RMID); // Semaphore remove
shmdt(pilotesTab); // SM detach
shmctl(shmid, IPC_RMID, 0); // SM remove
return 0;
}
下面是在控制台中显示输出的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sem.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <semaphore.h>
#include "CourseF1.h"
#include "ResultCourse.h"
#define MAX_PILOTES 22
void showResults(struct Pilote tab[], int nbElems, char* name) {
if (strcmp(name, "Race") != 0) { // NOT in Race
qsort(tab, nbElems, sizeof(Pilote), compareBest);
for (int k = 0; k < nbElems; k++) {
// If the pilote gave up during session
// But did a time
if (tab[k].hasGivenUp) {
printf(
"%d) voiture n°%d : Best S1 => %ds%dms | Best S2 => %ds%dms | Best S3 => %ds%dms | Best Lap => %dm%ds%dms || DNF\n",
k+1,
tab[k].pilote_id,
(tab[k].bestS1/1000)%60, tab[k].bestS1-(tab[k].bestS1/1000)*1000,
(tab[k].bestS2/1000)%60, tab[k].bestS2-(tab[k].bestS2/1000)*1000,
(tab[k].bestS3/1000)%60, tab[k].bestS3-(tab[k].bestS3/1000)*1000,
tab[k].best/60000, (tab[k].best/1000)%60, tab[k].best-(tab[k].best/1000)*1000
);
continue;
}
// If the pilote gave up during first lap
// HACK TIME to place it at the end of the list
if (tab[k].hasGivenUp && tab[k].best == (3 * 60 * 3600) + 1) {
printf("%d) voiture n°%d : // Abandon durant le premier tour de la session => Pas de temps // \n",
k+1,
tab[k].pilote_id
);
continue;
}
// If everything is OK
printf(
"%d) voiture n°%d : Best S1 => %ds%dms | Best S2 => %ds%dms | Best S3 => %ds%dms | Best Lap => %dm%ds%dms \n",
k+1,
tab[k].pilote_id,
(tab[k].bestS1/1000)%60, tab[k].bestS1-(tab[k].bestS1/1000)*1000,
(tab[k].bestS2/1000)%60, tab[k].bestS2-(tab[k].bestS2/1000)*1000,
(tab[k].bestS3/1000)%60, tab[k].bestS3-(tab[k].bestS3/1000)*1000,
tab[k].best/60000, (tab[k].best/1000)%60, tab[k].best-(tab[k].best/1000)*1000
);
}
} else { // IN race
for (int k = 0; k < nbElems; k++) {
qsort(tab, nbElems, sizeof(Pilote), compareTot);
if (tab[k].hasGivenUpDuringRace) {
printf("%d) voiture n°%d: DNF (n'a pas pu finir l'entiereté de la course pour cause d'abandon)\n",
k+1,
tab[k].pilote_id
);
continue;
}
printf(
"%d) voiture n°%d : Best S1 => %ds%dms | Best S2 => %ds%dms | Best S3 => %ds%dms | Best Lap => %dm%ds%dms || Total => %dm%ds%dms \n",
k+1,
tab[k].pilote_id,
(tab[k].bestS1/1000)%60, tab[k].bestS1-(tab[k].bestS1/1000)*1000,
(tab[k].bestS2/1000)%60, tab[k].bestS2-(tab[k].bestS2/1000)*1000,
(tab[k].bestS3/1000)%60, tab[k].bestS3-(tab[k].bestS3/1000)*1000,
tab[k].best/60000, (tab[k].best/1000)%60, tab[k].best-(tab[k].best/1000)*1000,
tab[k].totalTime/60000, (tab[k].totalTime/1000)%60, tab[k].totalTime-(tab[k].totalTime/1000)*1000
);
}
}
}
这是控制台中的错误输出:
1: voiture n°44: (0m0s0ms)
2: voiture n°6: (0m0s0ms)
3: voiture n°5: (0m0s0ms)
4: voiture n°0: (0m0s0ms)
5: voiture n°3: (0m0s0ms)
6: voiture n°0: (0m0s0ms)
7: voiture n°0: (0m0s0ms)
8: voiture n°0: (0m0s0ms)
9: voiture n°0: (0m0s0ms)
10: voiture n°0: (0m0s0ms)
11: voiture n°0: (0m0s0ms)
12: voiture n°0: (0m0s0ms)
13: voiture n°0: (0m0s0ms)
14: voiture n°0: (0m0s0ms)
15: voiture n°0: (0m0s0ms)
16: voiture n°0: (0m0s0ms)
17: voiture n°0: (0m0s0ms)
18: voiture n°0: (0m0s0ms)
19: voiture n°0: (0m0s0ms)
20: voiture n°0: (0m0s0ms)
21: voiture n°0: (0m0s0ms)
22: voiture n°0: (0m0s0ms)
希望说得够清楚,希望你能帮到我。
谢谢
您正在使用 System V 信号量,这很……古怪。 SysV 信号量有几个 POSIX 信号量没有的特性,但我发现 POSIX 信号量 API 更容易使用。 (另一方面,我有点喜欢共享内存段的 SysV 风格,尽管它也有一些怪癖。)
只要您使用的是 SysV 信号量,您就应该更加注意 semctl()
的文档。特别是:
The fourth argument is optional and depends upon the operation
requested. If required, it is of type union semun
, which the
application shall explicitly declare:
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
(POSIX specification for semctl()
)
当您使用四参数形式尝试设置信号量的初始值时,您传递了一个普通的 int
。 可能 看起来有效,但它不符合规范,因此行为未定义。
此外,由于您打算让 fork()
中的子进程继承您的共享内存段和信号量,而不是独立打开,因此我建议使用密钥 IPC_PRIVATE
每个而不是指定应用程序特定的密钥,尽管这与您观察到的不当行为无关。
但我认为你在这里面临的主要问题是你没有做任何事情来确保子进程在主进程检查结果之前完成它们的工作。在这种情况下,实现这一目标的最简单和最自然的方法是主程序,在分叉 所有 子级之后,为每个子级 wait()
或 waitpid()
他们。
作为奖励,您应该能够完全摆脱信号量,因为尽管子进程都访问同一个共享内存段,但没有两个访问它的同一部分。因此,它们不需要彼此同步。成功的等待足以确保父级与所有子级正确同步。
我的 c 程序有问题。
我已经在这里写了一个关于同一个程序的主题(我有 fork 的问题):
我正在模拟 F1 练习。现在分叉,我得到了一些不相关的数据(1/3 的汽车时间错误(0min0s0ms)。
我认为这是一个并发问题,所以我尝试 实现一个信号量 。
这样做的目的是一次只允许 1 个进程写入共享内存。
但是现在,我所有的输出数据都是错误的
例如:
- 大多数飞行员号码不正确(很多 n°0)。
- 他们都有不切实际的最佳时间 (0min 0sec 0ms)。
我注意到的一件事是,如果我删除增加信号量 1 (sem + 1) 的 sem 操作,在写入共享内存之前没有进程被阻塞但是他们应该因为信号量永远不会递增(它只是还在递减).
这是 "make the race":
的程序/* /!\ COMPILER AVEC -lm && -lpthread /!\ */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sem.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <wait.h>
#include "CourseF1.h"
#include "ResultCourse.h"
#define MAX_PILOTES 22
#define MAX_TOURS 44
int semid;
float ranf() { // PRNG for floats [0, 1].
float r = rand() / (float) RAND_MAX;
return r;
}
/**
*
* method based on Box-Muller transformation: https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
*
**/
float randGaussien(float m, float s) { /* median m, standard deviation s */
float x1, x2, w, y1, result;
float y2;
int use_last = 0;
if (use_last) /* use value of last call */
{
y1 = y2;
use_last = 0;
}
else
{
do {
x1 = 2.0 * ranf() - 1.0;
x2 = 2.0 * ranf() - 1.0;
w = x1 * x1 + x2 * x2;
} while ( w >= 1.0 );
w = sqrt( (-2.0 * log( w ) ) / w );
y1 = x1 * w;
y2 = x2 * w;
use_last = 1;
}
result = ( m + y1 * s );
if (result < 0) {
return 0.0;
}
return result;
}
int genTime(const int min, const int max) {
return ((rand() % (max-min + 1)) + min); // Generate a random number between min and max
}
int genRaceEvents(const int max) { // Decide about race events
return rand() % max; // Generate a number between 0 and max - 1
}
int compareBest(const void *p1, const void *p2) { // Compare the best times
const struct Pilote *elem1 = p1;
const struct Pilote *elem2 = p2;
if (elem1->best < elem2->best) return -1;
if (elem1->best > elem2->best) return 1;
return 0;
}
int compareTot(const void *p1, const void *p2) { // Compare the total times
const struct Pilote *elem1 = p1;
const struct Pilote *elem2 = p2;
if (elem1->totalTime < elem2->totalTime) return -1;
if (elem1->totalTime > elem2->totalTime) return 1;
return 0;
}
void fillTab(struct Pilote tabToFill[], struct Pilote tabFiller[], const int start, const int stop) {
for (int i = start; i < stop; i++) {
tabToFill[i] = tabFiller[i];
}
}
int run(Pilote *p, char* name) {
struct sembuf sem_op; // sembuf struct for semaphore operations
sem_op.sem_num = 0;
sem_op.sem_op = -1; // sem - 1
sem_op.sem_flg = 0;
if (semop(semid, &sem_op, 1) == -1) { // sem operation
perror("Error when decrementing semaphore");
}
/* Instantiation of Pilote struct values */
p->s1 = 3 * 60 * 3600 + 1;
p->bestS1 = 3 * 60 * 3600 + 1;
p->s2 = 3 * 60 * 3600 + 1;
p->bestS2 = 3 * 60 * 3600 + 1;
p->s3 = 3 * 60 * 3600 + 1;
p->bestS3 = 3 * 60 * 3600 + 1;
p->best = 3 * 60 * 3600 + 1;
p->totalTime = 0;
p->isPit = 0;
p->hasGivenUp = 0;
p->hasGivenUpDuringRace = 0;
p->numberOfPits = 0;
for (int i = 0; i < MAX_TOURS; i++) { // For every lap
p->isPit = 0; // At first he doesn't pit
if (!(p->hasGivenUp)) { // If the pilote didn't give up
int givingUpEvent = genRaceEvents(500); // Generate a number between 0 and 499
if (givingUpEvent == 14 && strcmp(name, "Race") == 0) { // If the pilote has given up (during race)
p->best = 3 * 60 * 3600;
p->hasGivenUpDuringRace = 1;
return 0; // Stop le pilote
}
else if (givingUpEvent == 14) { // If the pilote has given up (but not during race)
p->best = 3 * 60 * 3600 + 3;
p->hasGivenUp = 1;
return 0; // Stop the pilote
}
}
if (p->numberOfPits < 2) { // Max 2 stops
p->isPit = genRaceEvents(250); // Generate a number between 0 and 249
if (p->isPit) {
p->numberOfPits++;
if ((strcmp(name, "Practices") == 0)|| (strcmp(name, "Qualifs") == 0)) continue; // Next iteration
}
}
// We do a lap
int S1 = 0.275 * (103000 + randGaussien(5000, 2000)); // Portion of circuit * Gauss curve (min time + fun(median, standard deviation))
int S2 = 0.459 * (103000 + randGaussien(5000, 2000));
int S3 = 0.266 * (103000 + randGaussien(5000, 2000));
if ((strcmp(name, "Race") == 0) && (p->isPit)) { // If we are during race and the pilote pit
S1 += genTime(20 * 3600, 25 * 3600); // We add between 20 and 25sec at Sector 1
}
p->s1 = S1; // Notify time of S1
p->s2 = S2; // Notify time of S2
p->s3 = S3; // etc...
int lap = S1 + S2 + S3;
if (p->bestS1 > S1) p->bestS1 = S1; // If it's its best S1, we modify the best S1
if (p->bestS2 > S2) p->bestS2 = S2; // etc
if (p->bestS3 > S3) p->bestS3 = S3; // etc
if (p->best > lap) p->best = lap; // If it's its best lap time, we modify the best lap time,
if ((strcmp(name, "Race") == 0)) {
p->totalTime += lap; // add the lap time to the total race time
}
} // End of for loop
sem_op.sem_num = 0;
sem_op.sem_op = 1; // sem + 1
sem_op.sem_flg = 0;
if (semop(semid, &sem_op, 1) == -1) { // sem operation
perror("Error when incrementing semaphore");
}
}
int main(int argc, char const *argv[]) {
//srand (time(NULL)); // Useful for random number generation
printf("========================================\n");
for (int i = 0; i < 22; i++) {
printf("Random: %d\n", genRaceEvents(100));
}
printf("=========================================\n");
// Variables for the race
int pilotes_numbers[MAX_PILOTES] = {44, 6, 5, 7, 3, 33, 19, 77, 11, 27, 26, 55, 14, 22, 9, 12, 20, 30, 8, 21, 31, 94}; // Tab containing pilotes numbers
struct Pilote Q2[16]; // Tab of pilotes for Q2
struct Pilote Q3[10]; // Tab of pilotes for Q3
struct Pilote mainRun[MAX_PILOTES]; // Tab of pilotes for other race, practices
struct Pilote *pilotesTab; // pointer to SM
pid_t tabPID[MAX_PILOTES]; // Tab of PID
int shmid = 0; // SM id
key_t key; // Key for SM and Semaphores
/**
* Shared memory
*/
// Key generation for Shared Memory
key = ftok(argv[0], 123); // argv[O] => name of the program launched, ID (char)
// SM initialization
shmid = shmget(key, MAX_PILOTES * sizeof(Pilote), IPC_CREAT | 0644);
if (shmid == -1) {
perror("Erreur when allocating SM.");
return 0;
}
// Attach SM segment
pilotesTab = shmat(shmid, NULL, 0);
/**
* Semaphores
*/
// Semaphores initialization (1 semaphore)
semid = semget(key, 1, IPC_CREAT | 0640); // key, number of semaphores, perm
if(semid == -1) { // Erreur
perror("Error when creating semaphore");
return 0;
}
// Set semaphore value to 1
int rv = semctl(semid, 0, SETVAL, 1); // semid, sem number, operation type, union semun
if (rv == -1) { // sif return value == -1
perror("Error when affecting value to the semaphore");
return 0;
}
/**
* Fork
*/
int j;
for (j = 0; j < MAX_PILOTES; j++) { /* Create 22 processes */
tabPID[j] = fork();
if (tabPID[j] == -1) { // Error
perror("Error when forking\n");
return 0;
}
if (tabPID[j] == 0) { // Child
//
srand(time(NULL) ^ (getpid() << 16));
pilotesTab[j].pilote_id = pilotes_numbers[j]; // Pilote number initialization
run(&pilotesTab[j], "Practices");
exit(0);
}
} /* End of 22 processes */
printf("==================================================== \n");
fillTab(mainRun, pilotesTab, 0, MAX_PILOTES); // Fill the tab before sorting + show to the console
showResults(mainRun, MAX_PILOTES, "Practices");
printf("====================================================\n");
/**
* END TEST
*/
semctl(semid, 0, IPC_RMID); // Semaphore remove
shmdt(pilotesTab); // SM detach
shmctl(shmid, IPC_RMID, 0); // SM remove
return 0;
}
下面是在控制台中显示输出的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sem.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <semaphore.h>
#include "CourseF1.h"
#include "ResultCourse.h"
#define MAX_PILOTES 22
void showResults(struct Pilote tab[], int nbElems, char* name) {
if (strcmp(name, "Race") != 0) { // NOT in Race
qsort(tab, nbElems, sizeof(Pilote), compareBest);
for (int k = 0; k < nbElems; k++) {
// If the pilote gave up during session
// But did a time
if (tab[k].hasGivenUp) {
printf(
"%d) voiture n°%d : Best S1 => %ds%dms | Best S2 => %ds%dms | Best S3 => %ds%dms | Best Lap => %dm%ds%dms || DNF\n",
k+1,
tab[k].pilote_id,
(tab[k].bestS1/1000)%60, tab[k].bestS1-(tab[k].bestS1/1000)*1000,
(tab[k].bestS2/1000)%60, tab[k].bestS2-(tab[k].bestS2/1000)*1000,
(tab[k].bestS3/1000)%60, tab[k].bestS3-(tab[k].bestS3/1000)*1000,
tab[k].best/60000, (tab[k].best/1000)%60, tab[k].best-(tab[k].best/1000)*1000
);
continue;
}
// If the pilote gave up during first lap
// HACK TIME to place it at the end of the list
if (tab[k].hasGivenUp && tab[k].best == (3 * 60 * 3600) + 1) {
printf("%d) voiture n°%d : // Abandon durant le premier tour de la session => Pas de temps // \n",
k+1,
tab[k].pilote_id
);
continue;
}
// If everything is OK
printf(
"%d) voiture n°%d : Best S1 => %ds%dms | Best S2 => %ds%dms | Best S3 => %ds%dms | Best Lap => %dm%ds%dms \n",
k+1,
tab[k].pilote_id,
(tab[k].bestS1/1000)%60, tab[k].bestS1-(tab[k].bestS1/1000)*1000,
(tab[k].bestS2/1000)%60, tab[k].bestS2-(tab[k].bestS2/1000)*1000,
(tab[k].bestS3/1000)%60, tab[k].bestS3-(tab[k].bestS3/1000)*1000,
tab[k].best/60000, (tab[k].best/1000)%60, tab[k].best-(tab[k].best/1000)*1000
);
}
} else { // IN race
for (int k = 0; k < nbElems; k++) {
qsort(tab, nbElems, sizeof(Pilote), compareTot);
if (tab[k].hasGivenUpDuringRace) {
printf("%d) voiture n°%d: DNF (n'a pas pu finir l'entiereté de la course pour cause d'abandon)\n",
k+1,
tab[k].pilote_id
);
continue;
}
printf(
"%d) voiture n°%d : Best S1 => %ds%dms | Best S2 => %ds%dms | Best S3 => %ds%dms | Best Lap => %dm%ds%dms || Total => %dm%ds%dms \n",
k+1,
tab[k].pilote_id,
(tab[k].bestS1/1000)%60, tab[k].bestS1-(tab[k].bestS1/1000)*1000,
(tab[k].bestS2/1000)%60, tab[k].bestS2-(tab[k].bestS2/1000)*1000,
(tab[k].bestS3/1000)%60, tab[k].bestS3-(tab[k].bestS3/1000)*1000,
tab[k].best/60000, (tab[k].best/1000)%60, tab[k].best-(tab[k].best/1000)*1000,
tab[k].totalTime/60000, (tab[k].totalTime/1000)%60, tab[k].totalTime-(tab[k].totalTime/1000)*1000
);
}
}
}
这是控制台中的错误输出:
1: voiture n°44: (0m0s0ms)
2: voiture n°6: (0m0s0ms)
3: voiture n°5: (0m0s0ms)
4: voiture n°0: (0m0s0ms)
5: voiture n°3: (0m0s0ms)
6: voiture n°0: (0m0s0ms)
7: voiture n°0: (0m0s0ms)
8: voiture n°0: (0m0s0ms)
9: voiture n°0: (0m0s0ms)
10: voiture n°0: (0m0s0ms)
11: voiture n°0: (0m0s0ms)
12: voiture n°0: (0m0s0ms)
13: voiture n°0: (0m0s0ms)
14: voiture n°0: (0m0s0ms)
15: voiture n°0: (0m0s0ms)
16: voiture n°0: (0m0s0ms)
17: voiture n°0: (0m0s0ms)
18: voiture n°0: (0m0s0ms)
19: voiture n°0: (0m0s0ms)
20: voiture n°0: (0m0s0ms)
21: voiture n°0: (0m0s0ms)
22: voiture n°0: (0m0s0ms)
希望说得够清楚,希望你能帮到我。
谢谢
您正在使用 System V 信号量,这很……古怪。 SysV 信号量有几个 POSIX 信号量没有的特性,但我发现 POSIX 信号量 API 更容易使用。 (另一方面,我有点喜欢共享内存段的 SysV 风格,尽管它也有一些怪癖。)
只要您使用的是 SysV 信号量,您就应该更加注意 semctl()
的文档。特别是:
The fourth argument is optional and depends upon the operation requested. If required, it is of type
union semun
, which the application shall explicitly declare:union semun { int val; struct semid_ds *buf; unsigned short *array; } arg;
(POSIX specification for semctl()
)
当您使用四参数形式尝试设置信号量的初始值时,您传递了一个普通的 int
。 可能 看起来有效,但它不符合规范,因此行为未定义。
此外,由于您打算让 fork()
中的子进程继承您的共享内存段和信号量,而不是独立打开,因此我建议使用密钥 IPC_PRIVATE
每个而不是指定应用程序特定的密钥,尽管这与您观察到的不当行为无关。
但我认为你在这里面临的主要问题是你没有做任何事情来确保子进程在主进程检查结果之前完成它们的工作。在这种情况下,实现这一目标的最简单和最自然的方法是主程序,在分叉 所有 子级之后,为每个子级 wait()
或 waitpid()
他们。
作为奖励,您应该能够完全摆脱信号量,因为尽管子进程都访问同一个共享内存段,但没有两个访问它的同一部分。因此,它们不需要彼此同步。成功的等待足以确保父级与所有子级正确同步。