C Linux pthreads:使用共享内存将数据从一个线程发送到另一个线程会产生意外结果

时间:2022-09-06 18:50:52

I am writing a program that will transfer 50 integers from one thread to another using shared memory and upon receiving the integers the receiver thread will print them.

我正在编写一个程序,它将使用共享内存将50个整数从一个线程传输到另一个线程,并在接收到整数后,接收器线程将打印它们。

The code compiles without any errors or warnings but when I run it I get the following output:

代码编译时没有任何错误或警告,但是当我运行它时,我得到以下输出:

pthread_create() for thread 1 returns: 0
pthread_create() for thread 2 returns: 0
Segmentation fault (core dumped)

Here is my code so far:

这是我到目前为止的代码:

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

//define declarations
#define SIZE     50

//function declarations
void *send_data();
void *receive_data();

int main()
{
     pthread_t thread1;
     pthread_t thread2;
     int ret_val_t1;
     int ret_val_t2;

     //create thread1
     ret_val_t1 = pthread_create( &thread1, NULL, send_data, NULL);
     if(ret_val_t1)
     {
         fprintf(stderr,"Error - pthread_create() return value: %d\n",ret_val_t1);
         exit(EXIT_FAILURE);
     }

     //create thread2
     ret_val_t2 = pthread_create( &thread2, NULL, receive_data, NULL);
     if(ret_val_t2)
     {
         fprintf(stderr,"Error - pthread_create() return value: %d\n",ret_val_t2);
         exit(EXIT_FAILURE);
     }

     printf("pthread_create() for thread 1 returns: %d\n",ret_val_t1);
     printf("pthread_create() for thread 2 returns: %d\n",ret_val_t2);

     //wait untill threads are done with their routines before continuing with main thread
     pthread_join( thread1, NULL);
     pthread_join( thread2, NULL); 

     exit(EXIT_SUCCESS);
}

void *send_data(){
        int shmid;
    int *array;
    int i = 0;
    int SizeMem;
    key_t key = 12345;

    SizeMem = sizeof(*array)*SIZE;

    shmid = shmget(key, SIZE*sizeof(int), IPC_CREAT);

    array = (int *)shmat(shmid, 0, 0);


    for(i=0; i<SIZE; i++)
    {
          array[i] = i;
    }

    for(i=0; i<SIZE; i++)
    {
            printf("\n%d---\n", array[i]);
    }

    printf("\nWritting to memory succesful--\n");

    shmdt((void *) array);
}

void *receive_data(){
    int shmid;
    int *array;
    int i = 0;
    key_t key = 12345;

    shmid = shmget(key, SIZE*sizeof(int), IPC_EXCL);

    array = shmat(shmid, 0, SHM_RDONLY);

    for(i=0; i<SIZE; i++)
        {
            printf("\n%d---\n", array[i]);
        }

        printf("\nRead to memory succesful--\n");

        shmdt((void *) array);
}

3 个解决方案

#1


1  

Here in this situation, shared memory is a costly affair. And you are trying to access from the same process, there is no benefit here.

在这种情况下,共享内存是一种代价高昂的事情。而你试图从同一个过程访问,这里没有任何好处。

The better way to handle your situation is:

处理您的情况的更好方法是:

Threads of a parent process, will have access to parent process heap memory. This is simple concept to use. Create a heap object for the parent process and share across your threads.

父进程的线程将有权访问父进程堆内存。这是一个简单的概念。为父进程创建堆对象并在线程之间共享。

As said in many comments, shared memory is one of the "Inter Process Communication" communication concept, like pipes or named pipes or message queue etc....

正如许多评论中所说,共享内存是“进程间通信”通信概念之一,如管道或命名管道或消息队列等....

If you are using for practice, then it is OK. But as apart of PROD use, this is a costly affair.

如果您正在练习,那就没关系。但是,由于PROD的使用,这是一件昂贵的事情。

If you do not apply locks and access restriction to your mapped/shared memory properly, and you are not behind a secured firewall, then you are welcoming attackers.

如果您没有正确地对映射/共享内存应用锁定和访问限制,并且您没有安全防火墙,那么您欢迎攻击者。

#2


1  

One race condition arises from your code. Your second thread can get cpu first and try to use a non yet created memory segment. As it doesn't exist, and as you don't check for errors, you can get a SIGSEGV from trying to access memory at NULL address.

一个竞争条件来自您的代码。你的第二个线程可以先获得cpu并尝试使用一个尚未创建的内存段。由于它不存在,并且您没有检查错误,因此您可以通过尝试访问NULL地址处的内存来获取SIGSEGV。

You have to put synchronization devices that forbid the second thread to get to the shared memory access before it has been created and filled with data. Something like.

您必须放置同步设备,禁止第二个线程在创建并填充数据之前访问共享内存访问。就像是。

pthread_mutex_t lock;
pthread_cond_t shm_created_and_filled;

then in main you initialize the lock and shm_created_and_filled.

然后在main中初始化锁并shm_created_and_filled。

in the writing thread you will create the shared memory segment and write the numbers, finally locking and signalling the shm_created_and_filled condition variable. In the reading thread you first lock the lock variable and then wait for the shm_created_and_filled condition. There's still a little race condition in which the first thread runs and signals the shm_created_and_filled condition before the reading thread waits for it (it will lose the condition) but I have left it as an exercise for the reader.

在写入线程中,您将创建共享内存段并写入数字,最后锁定并发出shm_created_and_filled条件变量的信号。在读取线程中,首先锁定锁定变量,然后等待shm_created_and_filled条件。还有一点竞争条件,其中第一个线程运行并在读取线程等待它之前发出shm_created_and_filled条件(它将丢失条件),但我已将其作为练习器留给读者。

#3


0  

Use the ipcs utility and look at the output from ipcs -m

使用ipcs实用程序并查看ipcs -m的输出

Per the shmget man page:

根据shmget手册页:

SYNOPSIS top

大纲顶部

   #include <sys/ipc.h>
   #include <sys/shm.h>

   int shmget(key_t key, size_t size, int shmflg);

...

...

In addition to the above flags, the least significant 9 bits of shmflg specify the permissions granted to the owner, group, and others. These bits have the same format, and the same meaning, as the mode argument of open(2). Presently, execute permissions are not used by the system.

除了上述标志之外,shmflg的最低有效9位指定授予所有者,组和其他人的权限。这些位具有与open(2)的mode参数相同的格式和相同的含义。目前,系统不使用执行权限。

In line of code

在代码行

shmid = shmget(key, SIZE*sizeof(int), IPC_CREAT);

the "the least significant 9 bits of shmflg" are set to zero.

“shmflg的最低有效9位”设置为零。

No one has permissions to read/write your shared memory segment.

没有人有权读取/写入您的共享内存段。

This would be better:

这会更好:

shmid = shmget(key, SIZE*sizeof(int), IPC_CREAT | 0600 );

That would give the owning user read/write permission.

这将给拥有用户读/写权限。

#1


1  

Here in this situation, shared memory is a costly affair. And you are trying to access from the same process, there is no benefit here.

在这种情况下,共享内存是一种代价高昂的事情。而你试图从同一个过程访问,这里没有任何好处。

The better way to handle your situation is:

处理您的情况的更好方法是:

Threads of a parent process, will have access to parent process heap memory. This is simple concept to use. Create a heap object for the parent process and share across your threads.

父进程的线程将有权访问父进程堆内存。这是一个简单的概念。为父进程创建堆对象并在线程之间共享。

As said in many comments, shared memory is one of the "Inter Process Communication" communication concept, like pipes or named pipes or message queue etc....

正如许多评论中所说,共享内存是“进程间通信”通信概念之一,如管道或命名管道或消息队列等....

If you are using for practice, then it is OK. But as apart of PROD use, this is a costly affair.

如果您正在练习,那就没关系。但是,由于PROD的使用,这是一件昂贵的事情。

If you do not apply locks and access restriction to your mapped/shared memory properly, and you are not behind a secured firewall, then you are welcoming attackers.

如果您没有正确地对映射/共享内存应用锁定和访问限制,并且您没有安全防火墙,那么您欢迎攻击者。

#2


1  

One race condition arises from your code. Your second thread can get cpu first and try to use a non yet created memory segment. As it doesn't exist, and as you don't check for errors, you can get a SIGSEGV from trying to access memory at NULL address.

一个竞争条件来自您的代码。你的第二个线程可以先获得cpu并尝试使用一个尚未创建的内存段。由于它不存在,并且您没有检查错误,因此您可以通过尝试访问NULL地址处的内存来获取SIGSEGV。

You have to put synchronization devices that forbid the second thread to get to the shared memory access before it has been created and filled with data. Something like.

您必须放置同步设备,禁止第二个线程在创建并填充数据之前访问共享内存访问。就像是。

pthread_mutex_t lock;
pthread_cond_t shm_created_and_filled;

then in main you initialize the lock and shm_created_and_filled.

然后在main中初始化锁并shm_created_and_filled。

in the writing thread you will create the shared memory segment and write the numbers, finally locking and signalling the shm_created_and_filled condition variable. In the reading thread you first lock the lock variable and then wait for the shm_created_and_filled condition. There's still a little race condition in which the first thread runs and signals the shm_created_and_filled condition before the reading thread waits for it (it will lose the condition) but I have left it as an exercise for the reader.

在写入线程中,您将创建共享内存段并写入数字,最后锁定并发出shm_created_and_filled条件变量的信号。在读取线程中,首先锁定锁定变量,然后等待shm_created_and_filled条件。还有一点竞争条件,其中第一个线程运行并在读取线程等待它之前发出shm_created_and_filled条件(它将丢失条件),但我已将其作为练习器留给读者。

#3


0  

Use the ipcs utility and look at the output from ipcs -m

使用ipcs实用程序并查看ipcs -m的输出

Per the shmget man page:

根据shmget手册页:

SYNOPSIS top

大纲顶部

   #include <sys/ipc.h>
   #include <sys/shm.h>

   int shmget(key_t key, size_t size, int shmflg);

...

...

In addition to the above flags, the least significant 9 bits of shmflg specify the permissions granted to the owner, group, and others. These bits have the same format, and the same meaning, as the mode argument of open(2). Presently, execute permissions are not used by the system.

除了上述标志之外,shmflg的最低有效9位指定授予所有者,组和其他人的权限。这些位具有与open(2)的mode参数相同的格式和相同的含义。目前,系统不使用执行权限。

In line of code

在代码行

shmid = shmget(key, SIZE*sizeof(int), IPC_CREAT);

the "the least significant 9 bits of shmflg" are set to zero.

“shmflg的最低有效9位”设置为零。

No one has permissions to read/write your shared memory segment.

没有人有权读取/写入您的共享内存段。

This would be better:

这会更好:

shmid = shmget(key, SIZE*sizeof(int), IPC_CREAT | 0600 );

That would give the owning user read/write permission.

这将给拥有用户读/写权限。