子进程无法获取共享内存区域中的互斥锁

时间:2013-08-27 16:56:46

标签: c ipc mutex shared-memory atomicity

我正在尝试使用IPC,我想出了一个涉及Mutex的基本示例。这是一个修剪版本,以突出显示错误。没有互斥锁的代码按预期工作,子进程可以从父进程修改的SHM区域读取值。但是,在此版本中,只要父级释放互斥锁,子级就无法获取它并且它会卡在块中。我正在使用“kbhit.h”来简化键盘界面。代码也附在下面。如果有人知道为什么会这样,请分享知识。

程序片段:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <pthread.h>
#include <sys/mman.h>
#include "kbhit.h"

typedef struct {
    pthread_cond_t cond;
    pthread_condattr_t condattr;
    pthread_mutex_t mutex;
    pthread_mutexattr_t mutexattr;
    int status;
} IPCData;

int main(int argc, char const *argv[])
{
    IPCData* sharedMemory;
    pid_t childPID; //child process PID returned by fork
    char ch='x';

    sharedMemory = (IPCData*)mmap(NULL, sizeof(IPCData), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

    if ((void*)sharedMemory == -1){
        printf("Memory mapping failed\n");
        return -1;
    }

    sharedMemory->status = 1; //Set shared variable value

    if (pthread_condattr_init(&(sharedMemory->condattr)) != 0 && pthread_condattr_setpshared(&(sharedMemory->condattr), PTHREAD_PROCESS_SHARED) != 0){
        printf("Error initializing and setting condition variable attribute values\n");
        return -1;
    }

    if (pthread_cond_init(&(sharedMemory->cond), &(sharedMemory->condattr)) !=0){
        printf("Error initializing condition variable with attribute\n");
        return -1;
    }

    if (pthread_mutexattr_init(&(sharedMemory->mutexattr)) != 0 && pthread_mutexattr_setpshared(&(sharedMemory->mutexattr), PTHREAD_PROCESS_SHARED) != 0){
        printf("Error initializing mutex attribute and set to process shared\n");
        return -1;
    }

    if (pthread_mutex_init(&(sharedMemory->mutex), &(sharedMemory->mutexattr)) !=0){
        printf("Error initializing mutex with attributes\n");
        return -1;
    }

    //forking
    switch (childPID = fork()){
        case -1:
            printf("Failure to fork new child process\n");
            return -1;
        case 0:
            //child process
            printf("Child Started\n");
            while (__sync_fetch_and_add(&(sharedMemory->status), 0) !=0){ //atomically vertify variable value to continue execution as long as value !=0
                printf("Child - Looping, Status: %d\n", sharedMemory->status);
                //child fails to acquire lock after parent release it in SHM region
                pthread_mutex_lock(&(sharedMemory->mutex)); //acquire lock
                printf("Child Mutex Acquired\n");
                if (__sync_fetch_and_add(&(sharedMemory->status), 0) > 1) {printf("Increment Detected. Status: %d\n", sharedMemory->status);}
                printf("Child Mutex Released\n");
                pthread_mutex_unlock(&(sharedMemory->mutex)); //release lock
            }
            printf("Child Exiting\n");
            _Exit(3);
            break;
        default:
            //parent process

            init_keyboard();

            while(ch != 'q') {
                if (kbhit()) {
                    do{
                        ch=readch();
                    } while(kbhit());
                    if (ch == 's'){
                        pthread_mutex_lock(&(sharedMemory->mutex));
                        printf("Parent Mutex Acquired\n");
                        printf("Subbing\n");
                        printf("Status: %d\n", __sync_fetch_and_sub(&(sharedMemory->status), 1));
                        printf("Parent Mutex Released\n");
                        pthread_mutex_unlock(&(sharedMemory->mutex));
                    } else if (ch == 'a'){
                        pthread_mutex_lock(&(sharedMemory->mutex));
                        printf("Parent Mutex Acquired\n");
                        printf("Adding\n");
                        printf("Status: %d\n", __sync_fetch_and_add(&(sharedMemory->status), 1));
                        printf("Parent Mutex Released\n");
                        pthread_mutex_unlock(&(sharedMemory->mutex));
                    } else if (ch == 'z'){
                        printf("Returning value(Adding 0)\n");
                        printf("Status: %d\n", __sync_fetch_and_add(&(sharedMemory->status), 0));
                    }
                }
            }
            printf("Parent Exiting\n");
            close_keyboard();
            break;
    }

    pthread_condattr_destroy(&(sharedMemory->condattr));
    pthread_cond_destroy(&(sharedMemory->cond));
    pthread_mutexattr_destroy(&(sharedMemory->mutexattr));
    pthread_mutex_destroy(&(sharedMemory->mutex));

    if (munmap(sharedMemory, sizeof(IPCData)) == -1){
        printf("Unmap shared memory region failed\n");
        return -1;
    }

    return 0;
}

kbhit.h

#ifndef KBHITh
#define KBHITh

#include <termios.h>
#include <unistd.h>   // for read()

void   init_keyboard(void);
void   close_keyboard(void);
int      kbhit(void);
int     readch(void); 

static struct termios initial_settings, new_settings;
static int peek_character = -1;

void init_keyboard()
{
    tcgetattr(0,&initial_settings);
    new_settings = initial_settings;
    new_settings.c_lflag &= ~ICANON;
    new_settings.c_lflag &= ~ECHO;
    new_settings.c_lflag &= ~ISIG;
    new_settings.c_cc[VMIN] = 1;
    new_settings.c_cc[VTIME] = 0;
    tcsetattr(0, TCSANOW, &new_settings);
}

void close_keyboard()
{
    tcsetattr(0, TCSANOW, &initial_settings);
}

int kbhit()
{
unsigned char ch;
int nread;

    if (peek_character != -1) return 1;
    new_settings.c_cc[VMIN]=0;
    tcsetattr(0, TCSANOW, &new_settings);
    nread = read(0,&ch,1);
    new_settings.c_cc[VMIN]=1;
    tcsetattr(0, TCSANOW, &new_settings);
    if(nread == 1) 
    {
        peek_character = ch;
        return 1;
    }
    return 0;
}

int readch()
{
char ch;

    if(peek_character != -1) 
    {
        ch = peek_character;
        peek_character = -1;
        return ch;
    }
    read(0,&ch,1);
    return ch;
}


#endif

在使用代码后,不确定发生了什么,它按预期运行。下面是使用跨进程的条件变量和互斥量的IPC的示例;特别是在父母和孩子之间。

如何玩代码:

  1. 使用-lpthread编译并在同一目录中包含上面的“kbhit.h”

  2. 按键盘上的'v'检查驻留在SHM中的3个常用变量的值

  3. 按键盘上的'c'更改其中一个变量的值(增量)

  4. 再次按'v'确认

  5. 退出:

    1.按'k'修改变量值

    2.再次按'c',因为在退出循环之前,孩子将在cond等待时被阻止

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <pthread.h>
    #include <sys/mman.h>
    #include "kbhit.h"
    
    typedef struct {
        pthread_cond_t cond;
        pthread_condattr_t condattr;
        pthread_mutex_t mutex;
        pthread_mutexattr_t mutexattr;
        int status;
        int jobsignal;
        int count;
    } IPCData;
    
    int main(int argc, char const *argv[])
    {
        IPCData* sharedMemory;
        pid_t childPID; //child process PID returned by fork
        char ch='x';
    
        sharedMemory = (IPCData*)mmap(NULL, sizeof(IPCData), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    
        if ((void*)sharedMemory == -1){
            printf("Memory mapping failed\n");
            return -1;
        }
    
        sharedMemory->status = 1; //set shared variable value 1 = execute 0 = terminate
        sharedMemory->jobsignal = 0; //turn off Signal status 1 = job exist 0 = no job
        sharedMemory->count = 0; //common count variable
    
        if (pthread_condattr_init(&(sharedMemory->condattr)) != 0 || pthread_condattr_setpshared(&(sharedMemory->condattr), PTHREAD_PROCESS_SHARED) != 0){
            printf("Error initializing and setting condition variable attribute values\n");
            return -1;
        }
    
        if (pthread_cond_init(&(sharedMemory->cond), &(sharedMemory->condattr)) !=0){
            printf("Error initializing condition variable with attribute\n");
            return -1;
        }
    
        if (pthread_mutexattr_init(&(sharedMemory->mutexattr)) != 0 || pthread_mutexattr_setpshared(&(sharedMemory->mutexattr), PTHREAD_PROCESS_SHARED) != 0){
            printf("Error initializing mutex attribute and set to process shared\n");
            return -1;
        }
    
        if (pthread_mutex_init(&(sharedMemory->mutex), &(sharedMemory->mutexattr)) !=0){
            printf("Error initializing mutex with attributes\n");
            return -1;
        }
    
        //forking
        switch (childPID = fork()){
            case -1:
                printf("Failure to fork new child process\n");
                return -1;
            case 0:
                //child process
                printf("Child Process Started\n");
                while (__sync_fetch_and_add(&(sharedMemory->status), 0) !=0 ){ //atomically vertify variable value to continue execution as long as value !=0
                    if (pthread_mutex_lock(&(sharedMemory->mutex)) != 0) { //acquire lock
                        printf("Child Process Mutex Acquisition Failed\n");
                    } else {
                        printf("Child Process Mutex Acquisition Success\n");
                        if (pthread_cond_wait(&(sharedMemory->cond), &(sharedMemory->mutex)) != 0){
                            printf("Child Process Condition Wait Failed\n");
                        } else {
                            printf("Child Process Condition Wait Success\n");
                        }
                        __sync_fetch_and_add(&(sharedMemory->count), 1); //add 1
                        if (pthread_mutex_unlock(&(sharedMemory->mutex)) != 0) { //release lock
                            printf("Child Process Mutex Released Failed\n");
                        } else {
                            printf("Child Process Mutex Release Success\n");
                        }
                    }           
                }
                printf("Child Process Exiting\n");
                _Exit(3);
                break;
            default:
                //parent process
                printf("Parent Process Started\n");
                init_keyboard();
    
                while(ch != 'q') {
                    if (kbhit()) {
                        do{
                            ch=readch();
                        } while(kbhit());
                        if (ch == 'c'){
                            if (pthread_mutex_lock(&(sharedMemory->mutex)) != 0) {
                                printf("Parent Process Mutex Acquisition Failed\n");
                            } else {
                                printf("Parent Process Mutex Acquisition Success\n");
                                if (pthread_cond_signal(&(sharedMemory->cond)) != 0){
                                    printf("Parent Process Signal Failed\n");
                                } else {
                                    printf("Parent Process Signal Success\n");
                                }
                                if (pthread_mutex_unlock(&(sharedMemory->mutex)) != 0){
                                    printf("Parent Process Mutex Release Failed\n");
                                } else {
                                    printf("Parent Process Mutex Release Success\n");
                                }
                            }
                        } else if (ch == 'v'){
                            printf("Status: %d\n", __sync_fetch_and_add(&(sharedMemory->status), 0));
                            printf("JobSignal: %d\n", __sync_fetch_and_add(&(sharedMemory->jobsignal), 0));
                            printf("Count: %d\n", __sync_fetch_and_add(&(sharedMemory->count), 0));
                        } else if (ch == 'k'){
                            printf("Terminating Child Process\n");
                            __sync_fetch_and_sub(&(sharedMemory->status), 1);
                        }
                    }
                }
                printf("Parent Process Exiting\n");
                close_keyboard();
                break;
        }
    
        pthread_condattr_destroy(&(sharedMemory->condattr));
        pthread_cond_destroy(&(sharedMemory->cond));
        pthread_mutexattr_destroy(&(sharedMemory->mutexattr));
        pthread_mutex_destroy(&(sharedMemory->mutex));
    
        if (munmap(sharedMemory, sizeof(IPCData)) == -1){
            printf("Unmap shared memory region failed\n");
            return -1;
        }
    
        return 0;
    }
    

1 个答案:

答案 0 :(得分:1)

您不能使用pthread_mutex同步不同的进程,只能使用同一进程的线程。如果您可以使用它,请使用ipc管道,然后您不需要同步访问不同的数据结构。

编辑:

只是用Google搜索,似乎有时你可以设置正确的属性,抱歉