同一系统不同进程间的同步与互斥

本文详细介绍了互斥锁在多进程通信中的应用,包括初始化、设置属性、销毁等操作,以及互斥锁的类型。通过示例展示了如何使用互斥锁和共享内存进行进程间的同步,防止数据竞争。同时,提供了两个C++程序,分别作为读写进程,演示了如何在共享内存中使用互斥锁进行计数操作。
摘要由CSDN通过智能技术生成

 

1.函数原型:

// 初始化互斥对象属性
int pthread_mutexattr_init(pthread_mutexattr_t *attr);

// 设置互斥锁范围
int pthread_mutexattr_setpshared(pthread_mutexattr_t *mattr, int pshared);

//获取互斥锁范围
int pthread_mutexattr_getpshared(pthread_mutexattr_t *mattr, int *pshared);

// 销毁互斥对象属性
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);

    函数pthread_mutexattr_init()用该实现定义的所有属性的默认值初始化互斥对象属性attr。初始化一个已经初始化的互斥对象的效果是未定义的。在一个互斥锁属性对象被用于初始化一个或多个互斥锁之后,任何影响属性对象的函数(包括撤销)都不会影响任何先前初始化的互斥锁。pthread_mutexattr_destroy()函数的作用是:销毁互斥对象属性;实际上,对象变成未初始化的。一个实现可能导致pthread_mutexattr_destroy()将attr引用的对象设置为一个无效的值。销毁的互斥对象可以使用pthread_mutexattr_init()重新初始化;在对象被撤销后引用它的结果是未定义的。 

    互斥锁 变量可以是进程专用的(进程内)变量,也可以是系统范围内的(进程间)变量。要在多个进程中的线程之间共享 互斥锁,可以在 共享内存中创建互斥锁,并将 pshared 属性设置为 PTHREAD_PROCESS_SHARED。 此行为与最初的 Solaris 线程实现中 mutex_init() 中的 USYNC_PROCESS 标志等效。

如果 互斥锁的 pshared 属性设置为 PTHREAD_PROCESS_PRIVATE,则仅有那些由同一个进程创建的线程才能够处理该互斥锁。

// 初始化互斥锁
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
              const pthread_mutexattr_t *restrict attr);

// 释放互斥锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);

       pthread_mutex_init() 函数用attr指定的属性初始化互斥对象引用的互斥对象。如果attr为NULL,则使用默认的互斥锁属性;其效果与传递默认互斥对象的地址相同。成功初始化后,互斥锁的状态变为初始化和解锁。试图初始化一个已经初始化的互斥锁会导致未定义的行为。pthread_mutex_destroy()函数的作用是:销毁被互斥对象引用的互斥对象;互斥对象实际上变成了未初始化的。一个实现可能导致pthread_mutex_destroy()将mutex_引用的对象设置为一个无效的值。销毁的互斥对象可以使用pthread_mutex_init()重新初始化;在对象被撤销后引用它的结果是未定义的。销毁已初始化的互斥锁是安全的。试图销毁锁定的互斥锁会导致未定义的行为。在默认互斥对象属性合适的情况下,可以使用宏PTHREAD_MUTEX_INITIALIZER初始化静态分配的互斥对象。其效果等同于调用pthread_mutex_init(),并将参数attr指定为NULL,但是不执行错误检查。

    如果成功,pthread_mutex_init()pthread_mutex_destroy()函数返回零。否则,将返回错误号来指示错误。如果实现了[EBUSY]和[EINVAL]错误检查,就好像它们在函数处理的一开始就被立即执行,并在修改由互斥指定的互斥的状态之前导致错误返回。

pthread_mutex_init()函数将在以下情况下失败:

// 系统缺乏必要的资源(除了内存)来初始化另一个互斥锁。
(EAGAIN)
// 内存不足,无法初始化互斥锁。
(ENOMEM)
// 调用者没有执行该操作的权限。
(EPERM)
// 实现检测到试图重新初始化互斥锁引用的对象,互斥锁是一个先前初始化但尚未销毁的互斥锁。
(EBUSY)
// 由attr指定的值无效。
(EINVAL)

pthread_mutex_destroy()函数可能在以下情况下失败:

// 当互斥对象被另一个线程锁定或引用(例如,当在pthread_cond_wait()或pthread_cond_timedwait()中使用时),该实现检测到试图销毁互斥对象引用的行为。
(EBUSY)
//互斥指定的值无效。
(EINVAL)

 2. 互斥锁属性

// 设置互斥锁属性
int pthread_mutexattr_settype(pthread_mutexattr_t *attr , int type);

// 获取互斥锁属性
int pthread_mutexattr_gettype(pthread_mutexattr_t *attr , int *type);

互斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。当前(glibc2.2.3,linuxthreads0.9)有四个值可供选择:

  * PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。

  * PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。

  * PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。

  * PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。

3. 其他锁操作

  锁操作主要包括加锁pthread_mutex_lock()、解锁pthread_mutex_unlock()和测试加锁 pthread_mutex_trylock()三个,不论哪种类型的锁,都不可能被两个不同的线程同时得到,而必须等待解锁。对于普通锁和适应锁类型,解锁者可以是同进程内任何线程;而检错锁则必须由加锁者解锁才有效,否则返回EPERM;对于嵌套锁,文档和实现要求必须由加锁者解锁,但实验结果表明并没有这种限制,这个不同目前还没有得到解释。在同一进程中的线程,如果加锁后没有解锁,则任何其他线程都无法再获得锁。

int pthread_mutex_lock(pthread_mutex_t *mutex)

int pthread_mutex_unlock(pthread_mutex_t *mutex)

int pthread_mutex_trylock(pthread_mutex_t *mutex)

  pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待。

4. 案例

// write.cpp
/**
 * 文件名: test.cpp
 * 作 者: 浩然
 * 功 能:  
 * 日 期: Tue 27 Apr 2021 04:33:02 PM CST
 **/

#include <stdio.h>
#include <pthread.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
 

int main()
{
    pthread_mutex_t *mutex;
    pthread_mutexattr_t attr;
    int fd = open("/studio3/mutex_mmap", O_RDWR | O_CREAT, 00777);
    if(fd < 0){
        printf("open mmap file error...");
    }
    int fdt = open("/studio3/mutex_mmapt", O_RDWR | O_CREAT, 00777);
    if(fdt < 0){
        printf("open mmapt file error...");
    }

    ftruncate(fd,sizeof(pthread_mutex_t ));
    ftruncate(fdt,sizeof(int));

    mutex = (pthread_mutex_t *)mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE,
                                            MAP_SHARED , fd, 0);
    int *p_shared = (int *)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE,
                                            MAP_SHARED , fdt, 0);
    *p_shared = 0;

    pthread_mutexattr_init(&attr);
    pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(mutex, &attr);

    while(1){

        pthread_mutex_lock(mutex);
        (*p_shared)++;
        printf("parent process value is: %d\n", *p_shared);
        sleep(5);
        pthread_mutex_unlock(mutex);
        sleep(2);
    }
    pthread_mutexattr_destroy(&attr);
    pthread_mutex_destroy(mutex);

    munmap(mutex, sizeof(pthread_mutex_t));
    munmap(p_shared, sizeof(int));
    close(fd);
    close(fdt);

    return 0;
}
// read.cpp
/**
 * 文件名: test.cpp
 * 作 者: 浩然
 * 功 能:  
 * 日 期: Tue 27 Apr 2021 04:33:02 PM CST
 **/

#include <stdio.h>
#include <pthread.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
 
int main()
{
    pthread_mutex_t *mutex;
    int fd = open("/studio3/mutex_mmap", O_RDWR | O_CREAT, 00777);
    if(fd < 0){
        printf("open mmap file error...");
    }
    int fdt = open("/studio3/mutex_mmapt", O_RDWR | O_CREAT, 00777);
    if(fdt < 0){
        printf("open mmapt file error...");
    }

    ftruncate(fd,sizeof(pthread_mutex_t));
    ftruncate(fdt,sizeof(int));

    mutex = (pthread_mutex_t *)mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE,
                                            MAP_SHARED , fd, 0);
    int *p_shared = (int *)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE,
                                            MAP_SHARED , fdt, 0);

    while(1){

        pthread_mutex_lock(mutex);
        (*p_shared)++;
        printf("parent process value is: %d\n", *p_shared);
        sleep(1);
        pthread_mutex_unlock(mutex);
        sleep(2);
    }
    pthread_mutexattr_destroy(&attr);
    pthread_mutex_destroy(mutex);

    munmap(mutex, sizeof(pthread_mutex_t));
    munmap(p_shared, sizeof(int));
    close(fd);
    close(fdt);

    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值