c - 如何在 GTK 应用程序(或 GTK 和控制台应用程序)之间共享内存?

标签 c memory gtk share

我正在尝试通信两个程序(在一个程序中我使用 GTK,在另一个程序中我使用 C 编程的标准 IO)。在两者中我都使用了 shmget。 shmat,...等,以传达它们。

但是我要完成这些工作却遇到了很多麻烦...两个程序都可以编译,但没有一个按照我的意图运行。

我真正想做的是将数据从服务器发送到控制客户端程序的客户端(在这个测试中只是在终端上打印数字),客户端程序将在收到来自服务器的信号后完成其执行。

不幸的是,我无法使用 GTK 做到这一点,但我几乎在控制台应用程序中做到了这一点,但是当它自动运行(没有用户交互)时,客户端会在 65516 次迭代后崩溃。在游戏程序中这可能是一个问题,但是对于某些应用程序,下面的代码可以令人满意地工作。

我的问题是:为什么在达到65516次交互(客户端程序上调用shmat函数)后会出现错误?

在我 future 的应用程序中,必须避免此错误,否则会使程序崩溃......

如何避免它并保持我的程序(客户端应用程序)无限期运行?

还有其他方法可以通过一个程序来控制另一个程序吗?哪一种可行或更实用?

文件 smh-02.h

#define  NOT_READY  -1
#define  FILLED     0
#define  TAKEN      1

struct Memory 
{
    int  status;
    int  data[4];
    int dado;     // I just add this data
};

文件 Console_server01.c

#include  <stdio.h>
#include  <stdlib.h>
#include  <sys/types.h>
#include  <sys/ipc.h>
#include  <sys/shm.h>

#include "shm-02.h"

#define RUN_WITH_USER   // Coment this line to user interactivity
                    // Or uncoment it to run automactic test indefinitely until segmented fail

 key_t          ShmKEY;
 int            ShmID;
 struct Memory  *ShmPTR;

//---------------------------------------------------------------------
void send_data(int info)
{
while(ShmPTR->status != TAKEN);

 ShmPTR->status  = NOT_READY;
 ShmPTR->dado = info;
 ShmPTR->status = FILLED;   //Server has informed client that the shared memory have been FILLED    
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
int main(int argc, char *argv[]) 
{

int info;

 ShmKEY = ftok(".", 'x');
 ShmID = shmget(ShmKEY, sizeof(struct Memory), IPC_CREAT | 0666);

 if (ShmID < 0) 
    { 
    printf("*** shmget error (server) ***\n");
    exit(1);    
    }

 ShmPTR = (struct Memory *) shmat(ShmID, NULL, 0);

 if ((int) ShmPTR == -1) 
    { 
    printf("*** shmat error (server) ***\n");
    exit(1);     
    }

send_data(55); // This will send some signal to the client establish connection

    info = 1;           //----- Value to RUN_REPEATLY ------

    do
    {
#ifdef RUN_WITH_USER    //----------------------------------
    printf("\n Type:");
    printf("\n [1] To move to RIGHT");
    printf("\n [2] To move to LEFT");
    printf("\n [3] To move to QUIT");
    printf("\n You choice is: ");
    scanf("%d",&info);
#endif              //----------------------------------
    send_data(info);
    }
    while(info != 3);

     shmdt((void *) ShmPTR);         //Server has detached its shared memory...
     shmctl(ShmID, IPC_RMID, NULL); //Server has removed its shared memory...

return 0;
}

文件 Console_client01.c

#include  <stdio.h>
#include  <stdlib.h>
#include <unistd.h>
#include  <sys/types.h>
#include  <sys/ipc.h>
#include  <sys/shm.h>

#include "shm-02.h"

int  main(void)
{
key_t          ShmKEY;
 int            ShmID;
 struct Memory  *ShmPTR;
ShmKEY = ftok(".", 'x');

int i = 0;  
int trigger = 0;    // trigger locked
ShmID = shmget(ShmKEY, sizeof(struct Memory), 0666);

    if (ShmID < 0)
        {
          printf("*** shmget error (client) ***\n");
        exit (1); //Client exits
        }

    do{
        ShmPTR = (struct Memory *) shmat(ShmID, NULL, 0);

        if ( (ShmPTR->status == FILLED)&&(trigger == 0) )
            {
            ShmPTR->status = TAKEN;
            trigger = 1;    // trigger pulled
            }

            while (ShmPTR->status != FILLED)
                {
                printf("\nWaiting status = FILLED\t|\t");
                switch(ShmPTR->status)
                {
                case -1:
                    printf("Current status = NOT_READY");
                    break;
                case 0:
                    printf("Current status = FILLED");
                    break;
                case 1:
                    printf("Current status = TAKEN");
                    break;
                }
                sleep(1); // Uncoment this line to better user interactivity
                }

        usleep(800);    // Uncoment this line to better user interactivity
        i++;
        printf("\ni = %d --/// | dado = %d ", i, ShmPTR->dado);

        if ((int) ShmPTR == -1) 
            {
            printf("*** shmat error (client) ***\n");
            exit(1);    //Client exits 
            }
        else
            {
            if (ShmPTR->dado == 55)
                {   
                printf("\nConnection ESTABLISHED"); //Go to the LEFT
                ShmPTR->status = TAKEN;
                }

            if (ShmPTR->dado == 3)  // Exiting Program
                {
                ShmPTR->status = TAKEN;     //Client has informed server data have been taken...
                shmdt((void *) ShmPTR); //Client has detached its shared memory...
                exit (0); //Client exits 
                }

            if (ShmPTR->dado == 1)
                {   
                printf("\n<--- move LEFT"); //Go to the LEFT
                ShmPTR->status = TAKEN;
                }

            if (ShmPTR->dado == 2)  
                {
                printf("\n---> move RIGHT");    // Go to the RIGHT
                ShmPTR->status = TAKEN;
                }

            if ( (ShmPTR->dado != 1)||(ShmPTR->dado != 2) )
                {
                printf("\nIdle | dado = %d",ShmPTR->dado ); //Doing NOTHING
                ShmPTR->status = TAKEN;
                }
            }

    }while (1); // 'Infinite' loop
 exit(0);
}

Running the programs_Picture

Error after 65516 interations_Picture

最佳答案

您不应该使用共享内存进行通信。它不是类型安全的并且很难正确编码。

你真正需要的是序列化。考虑使用JSON-RPC用于沟通。是的,它比原始内存操作慢得多,但更安全、更便携、更容易正常工作Some even use it for heavy and often loads, let alone occasional loads like GUI input.

关于c - 如何在 GTK 应用程序(或 GTK 和控制台应用程序)之间共享内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39708616/

相关文章:

c - 生成内存访问图的工具

c++ - 更新标签文本 GTK+ C++

c - 如何获取与终端关联的 session 的 session ID?

c++ - 请问一台电脑 'know'是怎样分配的内存?

java - 了解 Java 堆转储

c++ - GTKMM:如何将键盘事件附加到绘图区域?

编译 64 位 Linux 的 32 位 GTK+ 应用程序

c - c中的结构和标记 union

C链表使用tail在末尾插入节点

c - GTK3 - TextView 透明度以显示后面的应用程序