无法在消费者进程中调用sem_trywait函数,但能够获取POSIX信号量的值。

huangapple go评论63阅读模式
英文:

Unable to call sem_trywait function in consumer process while able to get POSIX semaphore value

问题

I am currently trying to solve issue with my multi-process project. In the process called sender(file sender.c, producer) I am able to modify unnamed semaphore value bu using sem_wait and sem_post functions, POSIX sempahore is in shared memory. Curiously, in the process called receiver.c(consumer), I am able to get semaphore value, but calling sem_trywait gives me segmentation fault error.

我目前正在尝试解决我的多进程项目中的问题。在名为sender(文件sender.c,生产者)的进程中,我能够使用sem_wait和sem_post函数来修改无名信号量的值,POSIX信号量位于共享内存中。但奇怪的是,在名为receiver.c(消费者)的进程中,我能够获取信号量的值,但调用sem_trywait会导致分段错误。

I am suspecting some issues with passing arguments(pass-by-reference vs. pass-by-value). Other cause of issue might be due to improper way of releasing/destroing semaphore - i am aware that currently this issue might not be solved properly. Both sender.c and receiver.c get the data structure (buffer_node struct) from static linking.

我怀疑传递参数时存在一些问题(按引用传递与按值传递)。问题的另一个原因可能是释放/销毁信号量的方式不正确 - 我意识到目前这个问题可能没有得到正确解决。sender.c和receiver.c都从静态链接中获取数据结构(buffer_node结构)。

Header file(only struct buffer_node is tested)

头文件(只测试了结构体buffer_node)

Sender process:

发送进程:

Receiver process:

接收进程:

Any help would be appreciated.

任何帮助将不胜感激。

英文:

I am currently trying to solve issue with my multi-process project. In the process called sender(file sender.c, producer) I am able to modify unnamed semaphore value bu using sem_wait and sem_post functions, POSIX sempahore is in shared memory. Curiously, in the process called receiver.c(consumer), I am able to get semaphore value, but calling sem_trywait gives me segmentation fault error.

I am suspecting some issues with passing arguments(pass-by-reference vs. pass-by-value). Other cause of issue might be due to improper way of releasing/destroing semaphore - i am aware that currently this issue might not be solved properly. Both sender.c and receiver.c get the data structure (buffer_node struct) from static linking.

I tested that code on both Ubuntu running on x64 processor and Raspbian(Raspberry PI) running on ARM processor, i also tried changing sem_trywait to sem_wait. Preferably, I would like to avoid changing to named semaphores.

Header file(only struct buffer_node is tested)

    #define _CBUFFAPI_H_

    #include <stdlib.h>     
    #include <signal.h>     
    #include "stdio.h"
    #include <semaphore.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/sem.h>
    #include <sys/mman.h>
    #include <assert.h>
    #include <sys/stat.h>      
    #include <fcntl.h>   

    #define BUFFER_SIZE    5
    #define SAMPLES_AMOUNT 240


    struct buffer_node {
        unsigned long int buffered_samples[SAMPLES_AMOUNT];
        sem_t semaphore;
        int sem_val;
    };

    struct cyclic_buffer {
        struct buffer_node buffer_elements[BUFFER_SIZE];
        unsigned int head;
        unsigned int tail;
        unsigned int full;
        unsigned int max;
    };

    /*cyclic_buffer* init_buffer();
    //void buffer_reset(cyclic_buffer* cb);
    //void buffer_free(cyclic_buffer* cb);
    //void buffer_put(cyclic_buffer* cb, unsigned int index);
    //unsigned int is_buffer_full(cyclic_buffer* cb);*/
    int get_sem_val(sem_t sem);

    #endif

Sender process:

    #include <stdlib.h>     
    #include <signal.h>     
    #include "stdio.h"
    #include <semaphore.h>
    #include "cbuffapi.h"
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/sem.h>
    #include <sys/mman.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <assert.h>
    #include <sys/stat.h>      
    #include <fcntl.h>   

    #define NAME           "/testmem"

    struct buffer_node * shm_buffer;

    void Handler(int signo)
    {
        //System Exit
        printf("\r\n END \r\n");
        sem_close(&(shm_buffer->semaphore));
        munmap(0, sizeof(struct buffer_node));
        shm_unlink(NAME);
        exit(0);
    }

    int main()
    {
        signal(SIGINT, Handler);
        int shm_cyclic_buffer_fd = shm_open(NAME, O_CREAT|O_RDWR|O_EXCL, 0666);
    
        if(shm_cyclic_buffer_fd < 0)
        {
            perror("shm_open()");
            return 1;
        }
    
        ftruncate(shm_cyclic_buffer_fd, sizeof(struct buffer_node));
        shm_buffer = (struct buffer_node*)mmap(0, sizeof(struct buffer_node), PROT_WRITE|PROT_READ,    MAP_SHARED, shm_cyclic_buffer_fd, 0);
    shm_buffer->sem_val = 67;
    sem_init(&(shm_buffer->semaphore), 1, 4);
    int test_sem_val = 15;
    
    while(1)
    {
	if(sem_trywait(&(shm_buffer->semaphore))==0)
	{
	    sem_getvalue(&(shm_buffer->semaphore), &test_sem_val);
	    printf("%d\n", test_sem_val);
	    shm_buffer->sem_val = shm_buffer->sem_val + 1;
	    printf("%d\n", shm_buffer->sem_val);
	    sleep(5);
	    sem_post(&(shm_buffer->semaphore));
	    sem_getvalue(&(shm_buffer->semaphore), &test_sem_val);
	    printf("%d\n", test_sem_val);
	}
	else if(sem_trywait(&(shm_buffer->semaphore))== -1)
	{	
	    printf("variable reading - overwriting impossible\n");
	}
	
	sleep(0.5);
    }
    return 0;
}

Receiver process:

#include <stdlib.h>     
#include <signal.h>     
#include "stdio.h"
#include <semaphore.h>
#include "cbuffapi.h"
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <assert.h>
#include <sys/stat.h>      
#include <fcntl.h>   

#define NAME           "/testmem"

int shared_memory_fd;
void Handler(int signo)
{
    //System Exit
    printf("\r\n END \r\n");
    munmap(0, sizeof(struct buffer_node));
    close(shared_memory_fd);
    shm_unlink(NAME);
    exit(0);
}

int main()
{
    signal(SIGINT, Handler);
    struct buffer_node* shm_buffer;
	
    int shared_memory_fd = shm_open(NAME, O_RDONLY, 0666);
	
    if(shared_memory_fd < 0)
    {
	perror("Impossible to get shared memory file descriptor");
	return 1;
    }
    printf("Shared memory ID ok\n");
    //memory mapping
    shm_buffer=(struct buffer_node*)mmap(0, sizeof(struct buffer_node), PROT_READ, MAP_SHARED, shared_memory_fd, 0);
	
    if(shm_buffer == (void *) -1)
    {
	perror("Cannot attach to shared memory");
	return 2;
    }
    printf("map ok");
    printf("shared memory ID ok\n");
    int test_sem_val = 1;

    while(1)
    {
	sem_getvalue(&(shm_buffer->semaphore), &test_sem_val);
	printf("%d\n", test_sem_val);
	printf("%d\n", shm_buffer->sem_val);
	sleep(5);
	if(sem_trywait(&(shm_buffer->semaphore)) == 0)
	{	
	    printf("%d\n", shm_buffer->sem_val);
	    sleep(1);
	    sem_post(&(shm_buffer->semaphore));
	}
	else
	{
	    printf("variable modified\n");
	    sleep(1);
	}
    }
    return 0;
}

Any help would be appreciated.

答案1

得分: 1

接收进程以只读模式 (O_RDONLY) 打开共享内存对象,并且该对象通过 mmap() 进行映射,使用只读保护(未设置 PROT_WRITE)。

共享内存中包含一个有效的 sem_t 信号量对象,但由于接收进程中的内存是只读的,任何接收进程尝试修改信号量对象的操作都会导致向该进程发送 SIGSEGV 信号。该信号的默认操作是以核心转储的方式终止进程。

sem_wait()sem_trywait()sem_timedwait()sem_post() 函数都需要对信号量进行写访问。而 sem_getvalue() 函数仅需要对信号量进行读访问。

英文:

The receiver process is opening the shared memory object in read-only mode (O_RDONLY) and the object is being mapped by mmap() with read-only protection (PROT_WRITE is not set).

The shared memory contains a valid sem_t semaphore object, but because the memory is read-only in the receiver process, any attempts by the receiver process to modify the semaphore object will result in a SIGSEGV signal being delivered to the process. The default action for that signal is to terminate the process with a core dump.

The sem_wait(), sem_trywait(), sem_timedwait() and sem_post() functions all require write access to the semaphore. The sem_getvalue() function only requires read access to the semaphore.

huangapple
  • 本文由 发表于 2023年5月24日 17:40:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76322134.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定