C Unix Xcode 再次出现错误

C Unix Xcode bug again

我在做一个大学项目,我们要用到Unix系统调用。 现在,我真的很难理解在我的项目中是否真的存在错误。这是因为,虽然它在终端中编译并且开始和结束时没有错误,但在 xcode 上我遇到了几个错误。

特别是,我在使用信号量时遇到错误。

我会尝试解释我收到的错误,但由于我的母语不是英语,如果我犯了一些错误,请提前原谅我。

首先,程序用fork()创建了多个child进程。它取决于有多少 clientei.txt 位于(i = 迭代器)。 我立即用信号量阻止 parent,我 运行 child 达到某个点,然后我用信号量阻止它并重新启动 parent.

此时,parent应该读取儿子发送的消息,调用函数打印log.txt中的内容并重启儿子。

然后 child 做其他事情(包括删除消息)并阻止。 parent 重新启动,并为随后的 children.

重复一切

虽然终端同步是完美的(一切都在正确的时间发生,没有错误)这 Linux 和 Mac,关于 XCode 我有几个错误:

semop: 资源暂时不可用(如果我创建了超过5个txt) semop:文件太大(如果我创建了 2 个以上)

with 2 相反给了我两个错误: semop 1:中断的系统调用(这在 运行ning 两个进程之后停止) semop 3:标识符已删除(在重新启动第二个进程时)

做C的时间不多了,不知道干什么。我想首先知道我是否需要担心(所以有一个错误),或者我必须保持安静,因为它是 xcode 中的一个错误。 如果有错误,我恳请您不要要求我大量更改代码。 这主要是因为它们快要过期了,我负担不起再做一遍。 如果可以的话,我还请您尽可能清楚。我懂足够的英语,但还不够 mother-tongue,我不能总是关注 Whosebug 上的回复。

代码在这里: https://www.dropbox.com/s/2utsb6r5d7kzzqj/xcode%2Bterminal.zip?dl=0 这个 zip 包含有这个问题的项目的一小部分。 终端版本有效。这个版本有一个makefile来简化编译。 xcode 版本不工作。它包含调试文件夹。实际上 xcode, txt 文件,它不会从根文件夹中读取代码所在的文件夹,该文件夹位于它创建编译的文件夹中。每个案例都有一个自述文件,详细说明了过程。

我尽量减少,我评论都是英文的。 我删除了不需要的代码,但我添加了包含所有使用的包含和函数的文件。

这里是代码:

main.c

    key_t key, key_2;
    int semid, semid_2;
    union semun arg;
    union semun arg_2;
    struct sembuf sb_2 = {0, -1, 0};
    char* nome_file;
    nome_file = (char*) malloc(sizeof(char*));
    int numero_clienti;

    //semaphore for all the child
    struct sembuf sb[numero_clienti];

    int i_c;
    for (i_c = 0; i_c < numero_clienti; i_c++) {
        sb[i_c].sem_num = i_c;
        sb[i_c].sem_op = -1;
        sb[i_c].sem_flg = 0;

    }
    //cretion of first SEMAPHORE
    {
        //key creation
        if ((key = ftok("cliente0.txt", 'J')) == -1)
        {
            perror("ftok");
            exit(EXIT_FAILURE);
        }
        //creation of the semaphore
        if ((semid = semget(key, numero_clienti, 0666 | IPC_CREAT | IPC_EXCL)) == -1)
        {
            perror("semget");
            exit(EXIT_FAILURE);
        }
        //set value of all child semaphore
        for (i_c = 0; i_c < numero_clienti; i_c++) {
            arg.val = 0;
            if (semctl(semid, i_c, SETVAL, arg) == -1)
            {
                perror("semctl");
                exit(EXIT_FAILURE);
            }
        }

    }
    //cretion of second SEMAPHORE
    {
        //key creation
        if ((key_2 = ftok("cliente1.txt", 'J')) == -1)
        {
            perror("ftok");
            exit(EXIT_FAILURE);
        }
        //creation of the semaphore
        if ((semid_2 = semget(key_2, 1, 0666 | IPC_CREAT | IPC_EXCL)) == -1)
        {
            perror("semget");
            exit(EXIT_FAILURE);
        }
        //set value of parent semaphore
        arg_2.val = 0;
        if (semctl(semid_2, 0, SETVAL, arg_2) == -1)
        {
            perror("semctl");
            exit(EXIT_FAILURE);
        }
    }

    while(fd > 0 && pid > 0){


        j++;

        close(fd);
        pid = fork();

        if(pid != 0)
        {
            i++;
            sprintf(nome_file, "./cliente%d.txt", i);
            fd = open(nome_file, O_RDONLY);
        }
        switch(pid)
        {
            //error case
            case -1:
            {
                perror("Error during fork.");
                exit(EXIT_FAILURE);
                break;
            }
            //child case
            case 0:
            {

                puts("Child: I'm a child");
                messaggio(numero_clienti, j);
                puts("Child: I have to do something");

                //Start parent
                sb_2.sem_op = 1;
                if (semop(semid_2, &sb_2, 1) == -1)
                {
                    perror("semop");
                    exit(1);
                }
                //, stop itself
                sb[j].sem_op = -1;
                if (semop(semid, &sb[j], 1) == -1)
                {
                    perror("semop");
                    exit(1);
                }

                printf("Child: I have to do something else %d\n", getpid());

                _exit(EXIT_SUCCESS);
                break;
            }
            //parent case
            default:
            {

                puts("Parent: I'm a parent");

                //Stop itself
                sb_2.sem_op = -1;
                if (semop(semid_2, &sb_2, 1) == -1)
                {
                    perror("semop padre");
                    exit(1);
                }

                puts("Parent: now I can send the message, my child is blocked");

                //restart child
                sb[j].sem_op = 1;
                if (semop(semid, &sb[j], 1) == -1)
                {
                    perror("semop");
                    exit(1);
                }
                //stop itself
                sb_2.sem_op = -1;
                if (semop(semid_2, &sb_2, 1) == -1)
                {
                    perror("semop");
                    exit(1);
                }

                puts("Parent: end of while");
                break;
            }
        }
    }
    puts("Parent: I can restart all my child");

    for (i_c = 0; i_c < numero_clienti; i_c++) {
        sb[i_c].sem_op = 1;
        if (semop(semid, &sb[i_c], 1) == -1)
        {
            perror("semop");
            exit(1);
        }
    }

    puts("I wait the end of my child...");
    while (wait(NULL) != -1);

    puts("All child end");

    //remove semaphore I create
    if (semctl(semid, 0, IPC_RMID, arg) == -1)
    {
        perror("semctl");
        exit(1);
    }

    if (semctl(semid_2, 0, IPC_RMID, arg_2) == -1)
    {
        perror("semctl");
        exit(1);
    }

    puts("FINE");
    return 0;

}

cliente.c

#include "cliente.h"

/**
 inside this function child do some thing.
 1. at this point it give control to parent after it create a message
 2. at this point it remove the message
 */
void messaggio(int numero_clienti, int num_j){
    key_t key, key_2;
    int semid, semid_2;
    struct sembuf sb[numero_clienti];
    int i_c;
    for (i_c = 0; i_c < numero_clienti; i_c++) {
        sb[i_c].sem_num = i_c;
        sb[i_c].sem_op = -1;
        sb[i_c].sem_flg = 0;

    }
    struct sembuf sb_2 = {0, -1, 0};

    if ((key = ftok("cliente0.txt", 'J')) == -1) {
        perror("ftok");
        exit(1);
    }

    if ((semid = semget(key, 1, 0)) == -1) {
        perror("semget");
        exit(1);
    }

    if ((key_2 = ftok("cliente1.txt", 'J')) == -1) {
        perror("ftok");
        exit(1);
    }

    if ((semid_2 = semget(key_2, 1, 0)) == -1) {
        perror("semget");
        exit(1);
    }
    //creation of a message
    //1. Restart parent
    sb_2.sem_op = 1;
    if (semop(semid_2, &sb_2, 1) == -1)
    {
        perror("semop");
        exit(1);
    }

    puts("cambio sem");
    //stop itself
    sb[num_j].sem_op = -1;
    if (semop(semid, &sb[num_j], 1) == -1)
    {
        perror("semop");
        exit(1);
    }
    //here it can move again
    puts("remove message");

    puts("Figlio: sono tornato attivo, mio padre aspetta");

}

你第一次做

nome_file = (char*) malloc(sizeof(char*));

分配 4 或 8 个字节(取决于您编译的平台:32 位或 64 位)。

那你就做

sprintf(nome_file, "./cliente%d.txt", i);

后者写入无效内存,因为 "./cliente%d.txt" 的长度为 14+1 个字符加上来自 i if i>9 的潜在位数或者如果 [=22] 的附加符号=].

要解决此问题,请分配所需内容:

nome_file = malloc(13 + 10 + 1 + 1); /* 13 for the filename, 
                                        10 for the digits, 
                                         1 for a potential sign, 
                                         1 the C-"strings" 0-terminator. */

这是一个非常丑陋的错误,预计将成为您代码中的主要问题。


此外 在函数 read_line() 的源代码(您链接的)中分配内存,您没有正确初始化,但稍后取决于其内容。

main.c:20

char* myb2 = (char*) malloc(sizeof(char*));

malloc() 不会初始化它分配的内存,所以要么:

char * myb2 = calloc(1, sizeof(char*));

的添加和额外调用

memset(mb2, 0, sizeof(char*));

调用 malloc() 之后。

这个bug也很讨厌。


另外^2 你应该使用 gcc 的选项构建 -std=c99 -D_XOPEN_SOURCE.

那是因为:

  1. 您正在使用仅从 C99 提供的 C 构造。通常是 VLA,因此通过明确声明 -std=c99

  2. 告诉编译器将代码视为 C99 代码
  3. To #define _XOPEN_SOURCE 是由 gcc 发布的,对于一些 header 你包含在你的项目中。


另外^3 你似乎不一定计算正确的客户端(文件)数量,至少如果你的文件是按照你链接的存档分发的:

main.c:82

system("ls cliente* | wc -l");

将其更改为:

system("ls cliente*.txt | wc -l");

如果上面描述的错误应该 return 更多文件,那么实际上有以下代码也会从 i 的某个值开始失败:

main.c:176

fd = open(nome_file, O_RDONLY);

以上操作的结果测试。使用了可能无效的 fd 并且臭名昭着的未定义行为正在接管。一切皆有可能。


最后一点:这主要是从来没有我们正在使用的工具中的错误。