我正忙着在linux paltform上使用共享内存。 Cosider以下代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#define SEM_NAME "mysem"
int main (int argc, char *argv[])
{
int fd, zero = 0;
int *ptr;
sem_t *mutex;
pid_t PID = getpid();
int mmap_prot = PROT_WRITE;
if (argc < 2)
{
printf(" Usage: Test [OPTION]\n\tW = Write Only\n\tR = Read Only\n");
return 1;
}
if (*argv[1] == 'W')
{
fd = open("Test_SHM", O_RDWR | O_CREAT, -1);
if (fd == -1)
perror("open");
write(fd, &zero, sizeof(int));
}
else
{
fd = open("Test_SHM", O_RDONLY| O_CREAT, -1);
if (fd == -1)
perror("open");
mmap_prot = PROT_READ;
}
ptr = mmap(NULL, sizeof(int), mmap_prot, MAP_SHARED, fd, 0);
close(fd);
if (ptr == MAP_FAILED)
{
perror("mmap");
return 1;
}
// create, initialize, and unlink semaphore
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
sem_unlink(SEM_NAME);
setbuf(stdout, NULL); /* stdout is unbuffered */
printf("Shared Mem ready..\n");
while(1)
{
sem_wait(mutex);
printf("PID %d Count: %d\n", PID, (*ptr)++);
sem_post(mutex);
sleep(1);
}
return 0;
}
如果我为只读共享内存启动应用程序,我会按预期在第一次*ptr
在主循环内递增时出现分段错误。
我正在开发一个抽象Linux共享内存的lib。
此lib将部署到第三方开发人员,这些开发人员将在嵌入式目标上实现我的应用程序的某些进程。
这个lib将在进程之间实现“全局变量”。我想知道我是否可以避免开发get
和set
函数并简单地返回已分配内存的地址。
如果访问权限错误,我想向调用者信息提供其代码中的错误信息。在终端上读取分段故障并且进程终止不会给用户提供良好的信息。
EDIT2
在@Ctx回答之后我尝试了以下解决方案,但它可以解决第一个分段错误。第二个触发标准分段故障和pogram终止。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <signal.h>
#include <stdbool.h>
#include <setjmp.h>
#define SEM_NAME "mysem"
#define TEST 1
jmp_buf env;
void segvhandler(int arg) {
longjmp(env, 1);
}
bool Test ( int *ptr, sem_t *mutex, pid_t PID)
{
#if (TEST == 1)
signal(SIGSEGV, segvhandler);
#elif (TEST == 2)
sig_t segvhandler_OLD = signal(SIGSEGV, segvhandler);
#endif
int val = setjmp(env);
if (val != 0)
{
printf("Segmentation fault catched.\n");
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return false;
}
sem_wait(mutex);
printf("PID %d Count: %d\n", PID, (*ptr)++);
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return true;
}
int main (int argc, char *argv[])
{
int fd, zero = 0;
int *ptr;
sem_t *mutex;
pid_t PID = getpid();
int mmap_prot = PROT_WRITE;
if (argc < 2)
{
printf(" Usage: Test [OPTION]\n\tW = Write Only\n\tR = Read Only\n");
return 1;
}
if (*argv[1] == 'W')
{
fd = open("Test_SHM", O_RDWR | O_CREAT, -1);
if (fd == -1)
perror("open");
write(fd, &zero, sizeof(int));
}
else
{
fd = open("Test_SHM", O_RDONLY| O_CREAT, -1);
if (fd == -1)
perror("open");
mmap_prot = PROT_READ;
}
ptr = mmap(NULL, sizeof(int), mmap_prot, MAP_SHARED, fd, 0);
close(fd);
if (ptr == MAP_FAILED)
{
perror("mmap");
return 1;
}
// create, initialize, and unlink semaphore
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
sem_unlink(SEM_NAME);
setbuf(stdout, NULL); /* stdout is unbuffered */
printf("Shared Mem ready..\n");
while(1)
{
Test (ptr, mutex, PID);
sleep(1);
}
return 0;
}
答案 0 :(得分:2)
根据<html>
<head>
<!-- script in head -->
<script type = "javascript/text">
function myFunction() {
var a;
var text = "";
for ( a = 0; a < 5; a++ ){
// if statements within the loop
if( a === 0 || a === 4 ) { // All conditionals must be within one set of parenthesis. You can have others within, but all must be contained in one.
text += "$<br />";
}
if( a === 1 || a === 3 ) {
text += "$$<br />";
}
if ( a === 2 ) {
text += "$$$<br />";
}
}
document.getElementById( "dollar" ).innerHTML = text;
}
</script>
</head>
<body>
<!-- button in body -->
<button onclick="myFunction()">Click This Button</button>
<p id="dollar"></p>
</body>
</html>
man page:
mmap()
答案 1 :(得分:1)
如果要在修改不起作用的情况下继续,可以为SIGSEGV安装信号处理程序,并使用(sig)setjmp / longjmp在定义的点继续执行:
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
jmp_buf env;
void segvhandler(int arg) {
siglongjmp(env, 1);
}
void somefunc(void) {
char *ptr = NULL;
signal(SIGSEGV, segvhandler);
if (!sigsetjmp(env, 1)) {
// Direct invocation, try the memory access
*ptr++;
}
signal(SIGSEGV, SIG_DFL);
}
int main (void) {
while (1) {
somefunc();
printf("One more iteration...\n");
}
exit(EXIT_SUCCESS); // Never reached
}
sigsetjmp(env, 1)
还会将阻塞的信号保存在env
中,当它的第二个参数为非零时,siglongjmp()
会恢复这些信号。否则,信号仍将在longjmp()
后被阻止,因为它不是来自信号处理程序的真正的 return 。
请记住,在进行相关内存访问之前,您应该只安装处理程序,然后将其卸载。
答案 2 :(得分:0)
调试器几分钟后显示程序在调用sem_wait()
时崩溃。
在调用sem_open()
之后插入:
if( SEM_FAILED == mutex )
{
perror( "sem_open failed" );
exit( EXIT_FAILURE );
}
然后移动声明:
sem_unlink(SEM_NAME);
到声明之前:
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
然后很明显,剩下的问题出在本声明中:
printf("PID %d Count: %d\n", PID, (*ptr)++);
导致总线错误信号升高。这个总线错误信号在第一次通过while()
循环时发生。
原因很简单。
printf()
语句,最后一个参数是尝试读取和写入内存映射文件,但内存映射仅用于(取决于命令行参数)&#39; PROT_READ&#39;允许阅读或'PROT_WRITE&#39;这允许写作。调用mmap()
的参数需要同时包含两个功能和open()
的调用
有模式:O_RDWR
。 (open()和mmap()模式需要匹配
答案 3 :(得分:0)
这是Ctx回答后的更正代码。我还发现THIS有助于说明为什么longjmp不是带信号的正确解决方案。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <signal.h>
#include <stdbool.h>
#include <setjmp.h>
#define SEM_NAME "mysem"
#define TEST 1
jmp_buf env;
void segvhandler(int arg) {
siglongjmp(env, 1);
}
bool Test ( int *ptr, sem_t *mutex, pid_t PID)
{
#if (TEST == 1)
signal(SIGSEGV, segvhandler);
#elif (TEST == 2)
sig_t segvhandler_OLD = signal(SIGSEGV, segvhandler);
#endif
int val = sigsetjmp(env, 1);
if (val != 0)
{
printf("Segmentation fault catched.\n");
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return false;
}
sem_wait(mutex);
printf("PID %d Count: %d\n", PID, (*ptr)++);
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return true;
}
int main (int argc, char *argv[])
{
int fd, zero = 0;
int *ptr;
sem_t *mutex;
pid_t PID = getpid();
int mmap_prot = PROT_WRITE;
if (argc < 2)
{
printf(" Usage: Test [OPTION]\n\tW = Write Only\n\tR = Read Only\n");
return 1;
}
if (*argv[1] == 'W')
{
fd = open("Test_SHM", O_RDWR | O_CREAT, -1);
if (fd == -1)
perror("open");
write(fd, &zero, sizeof(int));
}
else
{
fd = open("Test_SHM", O_RDONLY| O_CREAT, -1);
if (fd == -1)
perror("open");
mmap_prot = PROT_READ;
}
ptr = mmap(NULL, sizeof(int), mmap_prot, MAP_SHARED, fd, 0);
close(fd);
if (ptr == MAP_FAILED)
{
perror("mmap");
return 1;
}
// create, initialize, and unlink semaphore
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
sem_unlink(SEM_NAME);
setbuf(stdout, NULL); /* stdout is unbuffered */
printf("Shared Mem ready..\n");
while(1)
{
Test (ptr, mutex, PID);
sleep(1);
}
return 0;
}