线程同步之共享内存

线程同步的方法

  • 共享内存

​ 概念:共享内存是进程间通信(IPC)中最简单的方式之一,也是最快的IPC形式。共享内存允许两个或多个进程访问同一块内存。当一个进程改变了这块内存中的内容的时候,其他进程就可以察觉到这种更改。一旦这样的内存映射到共享它的进程的地址空间,这些进程间的数据传递将不再涉及到内核,即进程不再通过执行进入内核的系统调用来传递数据,而是这些进程通过共享内存来传递数据。

共享内存的实现步骤:
1.创建共享内存区,通过shmget实现。在物理内存中开辟一块共享内存区。
2.把这块共享内存区挂接映射到两个进程的地址空间上,通过shmat实现。
3.完成通信之后,撤销内存映射关系,通过shmdt进行脱离。
4.删除共享内存区,通过shmctl实现。

共享内存的特性:
共享内存是最快的进程间通信的方案。不管是管道还是消息队列都必须把用户数据拷贝至内核,然后接收方再从内核中拷进来。共要进行两次拷贝,而共享内存一旦映射成功,一个进程向共享内存区写入了数据,其他共享这个内存的所有进程就能立刻看到其中的内容。
共享内存没有提供同步与互斥的机制。这部分的功能需要自己完成。若一个进程正在想共享内存区中写数据,则在它做完这一步的操作前,别的进程不应该去读或者写数据。

函数原型:
int shmget(key_t key, size_t size, int shmflg);
参数:
key:进程间通信的键值,ftok的返回值
size:共享内存的大小
shmflg:标识函数的行为及共享内存的权限。取值如下:
IPC_CREAT:如果不存在就创建共享内存
IPC_EXCL:和IPC_CREAT搭配使用,如果已经存在,则返回失败
权限位:设置共享内存的访问权限
返回值:成功返回一个非负整数,即共享内存的标识符;失败返回-1

函数原型:
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数:
shmid:共享内存标识符,shmget的返回值
shmaddr:指定映射地址(若为NULL,则由系统自动指定)
shmflg:共享内存的访问权限和映射条件(通常为0),取值如下:
0:共享内存具有可读可写权限
SHM_RDONLY:映射的内存只读
返回值: 成功返回一个指针,指向共享内存第一个节;失败返回-1

函数原型:
int shmdt(const void *shmaddr);
参数:
shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1

函数原型:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:
shmid:由shmget返回的共享内存的标识码
cmd:将要采取的动作,有如下取值:
IPC_RMID:删除共享内存
IPC_SET:在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds数据结构中给出的值
IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值
SHM_LOCK:锁定共享内存段(超级用户)
SHM_UNLOCK:解锁共享内存段
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1

存在的问题:

#include 
#include 
#include 
#include 
#include 
#include 
int main()
{
    int segment_id;
    char *shared_memory;
    struct shmid_ds shmbuffer;
    int segment_size;
    const int shared_segment_size = 0x6400;                                                          /* 分配一个共享内存块 */
    segment_id = shmget(IPC_PRIVATE, shared_segment_size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR); /* 绑定到共享内存块 */
    shared_memory = (char *)shmat(segment_id, 0, 0);

    printf("shared memory attached at address %p\n", shared_memory); /* 确定共享内存的大小 */
    shmctl(segment_id, IPC_STAT, &shmbuffer);
    segment_size = shmbuffer.shm_segsz;

    printf("segment size: %d\n", segment_size);
    sprintf(shared_memory, "Hello, world.");                        /* 在共享内存中写入一个字符串 */
    shmdt(shared_memory);                                           /* 脱离该共享内存块 */

    shared_memory = (char *)shmat(segment_id, (void *)0x500000, 0); /* 重新绑定该内存块 */

    printf("shared memory reattached at address %p\n", shared_memory);
    printf("input data: %s\n", shared_memory);   /* 输出共享内存中的字符串 */
    shmdt(shared_memory);            /* 脱离该共享内存块 */
    shmctl(segment_id, IPC_RMID, 0); /* 释放这个共享内存块 */
    return 0;
}
  • 读写锁
  • 自旋锁

你可能感兴趣的:(linux,编码,c++)