进程锁线程锁(实现)

锁机制

锁的分类

1、互斥锁(Mutex):是一种最常用的锁类型,用于实现互斥访问,即同一时间只有一个线程或进程可以获得锁,并且其他线程或进程必须等待。互斥锁可以用于保护临界区,防止多个线程同时访问共享资源。在 POSIX 环境下,通常使用 pthread_mutex 来实现互斥锁。

2、读写锁(Read-Write Lock):也称为共享-排他锁。读写锁允许多个线程同时获取读锁来进行读操作,但只允许一个线程获取写锁来进行写操作。这样可以在读多写少的情况下提高并发性能。在 POSIX 环境下,可以使用 pthread_rwlock 来实现读写锁。

3、条件变量(Condition Variable):条件变量用于线程之间的通信和同步。线程可以在条件变量上等待某个条件满足,并在条件满足时被唤醒。通常与互斥锁一起使用,用于实现复杂的同步操作。在 POSIX 环境下,可以使用 pthread_cond 来实现条件变量。

4、自旋锁(Spin Lock):是一种忙等锁,当线程尝试获取锁时,如果锁已被其他线程持有,它会一直循环忙等直到获取到锁。自旋锁适用于对临界区的访问时间很短的场景,避免线程阻塞和切换带来的开销。在 POSIX 环境下,可以使用 pthread_spinlock 来实现自旋锁。

5、原子操作(Atomic Operation):原子操作是一种特殊的锁机制,用于在单个操作中保证数据的原子性。原子操作是不可中断的,即使在多线程或多进程环境中也不会出现竞争条件。原子操作常用于对共享变量进行简单的读写操作,如增加或减少计数等。

进程锁

用于多个独立的进程之间的通信和同步
实现方式
1、文件锁:使用文件系统的特性实现进程间的互斥。多个进程可以通过对同一个文件进行加锁来实现同步。例如,Linux 中的 flock() 函数和 fcntl() 函数可以实现文件锁。

2、System V 信号量:System V 信号量是一种传统的进程间通信机制,可以通过 semget()、semop() 等函数实现信号量的创建和操作,从而实现进程间的同步和互斥。

3、POSIX 信号量:POSIX 信号量是对 System V 信号量的一种改进,提供了更简单易用的接口。可以通过 sem_open()、sem_wait()、sem_post() 等函数实现 POSIX 信号量的操作。

4、共享内存:使用共享内存作为进程间的通信通道,可以通过互斥锁来控制多个进程对共享内存的访问。

5、命名管道(FIFO):通过命名管道可以实现多个进程之间的通信和同步。

共享内存和命名管道区别
效率比较:

共享内存:由于共享内存直接映射到进程的内存空间,数据的读写操作无需涉及内核态和用户态之间的数据拷贝,因此读写操作速度较快,是进程间通信中最高效的方式之一。共享内存适用于频繁的数据交换和大数据量的传输。

命名管道:命名管道是基于文件系统的通信方式,数据的读写需要经过内核态和用户态之间的数据拷贝,因此相较于共享内存而言,读写操作的效率相对较低。命名管道适用于少量数据传输和简单通信场景。

应用场景比较:

共享内存:适用于多个进程之间需要频繁交换大量数据的情况,比如实时的数据共享、图像处理、视频流传输等。在这些场景下,共享内存可以显著提高数据传输的效率。

命名管道:适用于不同进程之间简单的通信和少量数据传输的场景。例如,可以用于命令行工具之间的简单通信,或者在多个独立进程之间传递少量数据的情况。

需要注意的是,效率的高低取决于具体的应用场景和需求。共享内存在高性能和大数据量传输方面具有优势,但同时也需要考虑并发安全性和数据同步的问题。而命名管道在简单通信和少量数据传输的场景下较为方便,但不适合频繁传输大量数据。因此,在选择使用共享内存或命名管道时,应根据具体的数据传输需求和并发情况做出合理的选择。

代码实现

多个进程共享一个互斥锁

typedef struct __pthread_st {
	pthread_mutex_t mem_mutex;
}PthreadLock_t;
static PthreadLock_t *mptr = NULL; /* 互斥锁变量指针,互斥锁变量存放到共享内存 */

static int memlock_init()
{
    pthread_mutexattr_t mattr;

	mptr = mmap(0, sizeof(PthreadLock_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1 , 0);
    if (mptr == MAP_FAILED) 
	{
		printf("memlock_init mmap error\n");
		return -1;
    }

    pthread_mutexattr_init(&mattr);// 用于初始化一个互斥锁属性对象
    pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);//设置互斥锁的共享属性为 PTHREAD_PROCESS_SHARED,这意味着互斥锁可以在多个进程之间共享。
    pthread_mutex_init(&(mptr->mem_mutex), &mattr);//

	return 0;	
}

共享内存实现进程间通信
创建共享内存:
首先,一个进程(通常是服务端或创建者进程)需要创建共享内存区域,并将其映射到自己的内存空间。这可以通过 shmget 系统调用来创建共享内存,然后使用 shmat 系统调用将共享内存连接到进程的地址空间。

通信数据结构定义:
接下来,进程需要定义共享内存区域的数据结构,以便不同进程之间能够在共享内存上进行通信。这些数据结构可以包含消息队列、互斥锁、信号量等,以确保并发安全性和同步。

读写数据:
不同进程可以通过共享内存区域进行数据的读写操作。读写数据时,需要通过互斥锁或其他同步机制来确保数据的一致性和避免竞争条件。

分离共享内存:
当进程不再需要共享内存时,应该通过 shmdt 系统调用将共享内存从进程的地址空间分离,以释放内存资源。

删除共享内存(可选):
在所有使用共享内存的进程都不再需要时,可以通过 shmctl 系统调用并指定 IPC_RMID 参数来删除共享内存区域。
进程A

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>

#define SHM_SIZE 1024

int main() {
    key_t key = 1234;
    int shmid;
    char *shm;

    // 创建共享内存
    shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666);
    if (shmid < 0) {
        perror("shmget");
        exit(EXIT_FAILURE);
    }

    // 连接到共享内存
    shm = shmat(shmid, NULL, 0);
    if (shm == (char *)-1) {
        perror("shmat");
        exit(EXIT_FAILURE);
    }

    // 写入数据到共享内存
    strcpy(shm, "Hello from Process A!");

    // 分离共享内存
    shmdt(shm);

    return 0;
}

进程B

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

typedef struct {
    int readers; // 当前持有读锁的进程数量
    int writers; // 当前持有写锁的进程数量
    int pending_writers; // 等待获取写锁的进程数量
    int shared_data; // 共享数据
} SharedData;

static int sem_id_readers; // 读者数量信号量集ID
static int sem_id_writers; // 写者数量信号量集ID
static int sem_id_pending_writers; // 等待获取写锁的进程数量信号量集ID
static int shm_id; // 共享内存ID
static SharedData *shared_data_ptr; // 指向共享内存的指针

// 用于P操作的函数
static void semaphore_wait(int sem_id, int sem_num) {
    struct sembuf sem_buf;
    sem_buf.sem_num = sem_num;
    sem_buf.sem_op = -1;
    sem_buf.sem_flg = 0;
    semop(sem_id, &sem_buf, 1);
}

// 用于V操作的函数
static void semaphore_signal(int sem_id, int sem_num) {
    struct sembuf sem_buf;
    sem_buf.sem_num = sem_num;
    sem_buf.sem_op = 1;
    sem_buf.sem_flg = 0;
    semop(sem_id, &sem_buf, 1);
}

static int rwlock_init() {
    // 创建共享内存
    shm_id = shmget(IPC_PRIVATE, sizeof(SharedData), IPC_CREAT | 0666);
    if (shm_id == -1) {
        perror("shmget error");
        return -1;
    }

    // 将共享内存映射到进程的地址空间
    shared_data_ptr = (SharedData *)shmat(shm_id, NULL, 0);
    if ((intptr_t)shared_data_ptr == -1) {
        perror("shmat error");
        return -1;
    }

    // 初始化共享数据
    shared_data_ptr->readers = 0;
    shared_data_ptr->writers = 0;
    shared_data_ptr->pending_writers = 0;
    shared_data_ptr->shared_data = 0;

    // 创建信号量集,包括三个信号量:一个用于控制读者数量,一个用于控制写者数量,一个用于控制等待获取写锁的进程数量
    sem_id_readers = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
    sem_id_writers = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
    sem_id_pending_writers = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);

    if (sem_id_readers == -1 || sem_id_writers == -1 || sem_id_pending_writers == -1) {
        perror("semget error");
        return -1;
    }

    // 初始化信号量
    semctl(sem_id_readers, 0, SETVAL, 1); // 读者数量初始为1,表示读者可以进入
    semctl(sem_id_writers, 0, SETVAL, 1); // 写者数量初始为1,表示写者可以进入
    semctl(sem_id_pending_writers, 0, SETVAL, 1); // 等待获取写锁的进程数量初始为1

    return 0;
}

static void rwlock_rdlock() {
    semaphore_wait(sem_id_readers, 0); // P操作,获取读者数量信号量

    shared_data_ptr->readers++;

    if (shared_data_ptr->readers == 1) {
        // 第一个读者,需要阻塞写者
        semaphore_wait(sem_id_writers, 0); // P操作,获取写者数量信号量
    }

    semaphore_signal(sem_id_readers, 0); // V操作,释放读者数量信号量
}

static void rwlock_wrlock() {
    semaphore_wait(sem_id_pending_writers, 0); // P操作,获取等待获取写锁的进程数量信号量
    semaphore_wait(sem_id_readers, 0); // P操作,获取读者数量信号量
    semaphore_wait(sem_id_writers, 0); // P操作,获取写者数量信号量

    shared_data_ptr->pending_writers++;

    semaphore_signal(sem_id_readers, 0); // V操作,释放读者数量信号量

    // 等待所有读者结束
    semaphore_wait(sem_id_readers, 0); // P操作,获取读者数量信号量
    shared_data_ptr->pending_writers--;
    shared_data_ptr->writers++;

    if (shared_data_ptr->readers > 0 || shared_data_ptr->pending_writers > 0) {
        // 有读者或等待的写者,需要阻塞其他写者
        semaphore_signal(sem_id_writers, 0); // V操作,释放写者数量信号量
        semaphore_wait(sem_id_writers, 0); // P操作,获取写者数量信号量
    }

    semaphore_signal(sem_id_pending_writers, 0); // V操作,释放等待获取写锁的进程数量信号量
    semaphore_signal(sem_id_readers, 0); // V操作,释放读者数量信号量
}

static void rwlock_unlock() {
    semaphore_wait(sem_id_readers, 0); // P操作,获取读者数量信号量

    if (shared_data_ptr->writers > 0) {
        shared_data_ptr->writers--;
    } else if (shared_data_ptr->readers > 0) {
        shared_data_ptr->readers--;
    }

    if (shared_data_ptr->readers == 0 && shared_data_ptr->pending_writers > 0) {
        // 最后一个读者,且有等待的写者,释放写者
        semaphore_signal(sem_id_writers, 0); // V操作,释放写者数量信号量
    }

    semaphore_signal(sem_id_readers, 0); // V操作,释放读者数量信号量
}

static void rwlock_cleanup() {
    // 删除信号量集
    semctl(sem_id_readers, 0, IPC_RMID, 0);
    semctl(sem_id_writers, 0, IPC_RMID, 0);
    semctl(sem_id_pending_writers, 0, IPC_RMID, 0);

    // 解除共享内存映射
    shmdt(shared_data_ptr);

    // 删除共享内存
    shmctl(shm_id, IPC_RMID, 0);
}

int main() {
    if (rwlock_init() == -1) {
        return 1;
    }

    pid_t pid = fork();
    if (pid == -1) {
        perror("Fork error");
        return 1;
    } else if (pid == 0) {
        // 子进程进行读操作
        while (1) {
            rwlock_rdlock();
            printf("Child Process: Read shared_data = %d\n", shared_data_ptr->shared_data);
            rwlock_unlock();
            usleep(1000000); // 等待1秒
        }
    } else {
        // 父进程进行写操作
        while (1) {
            rwlock_wrlock();
            shared_data_ptr->shared_data++;
            printf("Parent Process: Wrote shared_data = %d\n", shared_data_ptr->shared_data);
            rwlock_unlock();
            usleep(500000); // 等待0.5秒
        }
    }

    rwlock_cleanup();

    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/mman.h>
void print_semaphore_value(sem_t *sem,char *str, int line, char *name) {
    int sval;
    if (sem_getvalue(sem, &sval) == 0) {
        printf("%s %s %d  %d\n", str, name, line, sval);
    } else {
        perror("sem_getvalue");
    }
}

int shared_data = 0;
typedef struct KeyMemRwMutex_st{
    sem_t RwLockSem;//读写互斥信号量
    sem_t readNumCount;//读者计数修改信号量
    sem_t readSem;//读信号量,阻塞读进程
    sem_t writeSem;//写信号量,阻塞写进程
    int readers;
    int writers;
} KeyMemRwMutex;

static KeyMemRwMutex *keyMemRwPtr = NULL;

int memlock_init() {
    keyMemRwPtr = (KeyMemRwMutex *)mmap(NULL, sizeof(KeyMemRwMutex), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
    if (keyMemRwPtr == MAP_FAILED) {
        printf("mmap err\n");
        return -1;
    }
    sem_init(&(keyMemRwPtr->RwLockSem), 1, 1);
    sem_init(&(keyMemRwPtr->readNumCount), 1, 1);
    sem_init(&(keyMemRwPtr->readSem), 1, 1);
    sem_init(&(keyMemRwPtr->writeSem), 1, 1);

    keyMemRwPtr->readers = 0;
    keyMemRwPtr->writers = 0;
    return 0;
}
//print_semaphore_value(&(keyMemRwPtr->writeSem), (char*)__func__, __LINE__,"");
void rwlock_rdlock() {
    sem_wait(&(keyMemRwPtr->RwLockSem));
    sem_post(&(keyMemRwPtr->RwLockSem));

    // 读者数量计数互斥
    sem_wait(&(keyMemRwPtr->readNumCount));
    keyMemRwPtr->readers++;
    //第一个读者时 阻塞写者
    if (keyMemRwPtr->readers == 1) {
        print_semaphore_value(&(keyMemRwPtr->writeSem), (char*)__func__, __LINE__,"writeSem");
        print_semaphore_value(&(keyMemRwPtr->readSem), (char*)__func__, __LINE__,"readSem");
        sem_wait(&(keyMemRwPtr->writeSem));//writeSem - 1
    }
    sem_post(&(keyMemRwPtr->readNumCount));

}

void rwlock_wrlock() {
    sem_wait(&(keyMemRwPtr->RwLockSem));
    sem_wait(&(keyMemRwPtr->writeSem));
    keyMemRwPtr->writers++;
    if (keyMemRwPtr->writers == 1) {
        sem_wait(&(keyMemRwPtr->readSem));
    }
    sem_post(&(keyMemRwPtr->RwLockSem));
}

// 读写锁解锁(包含读解锁和写解锁)
void rwlock_unlock(char RwFlag) {
    if (RwFlag == 'r') {
        // 读者数量计数互斥
        sem_wait(&(keyMemRwPtr->readNumCount));
        keyMemRwPtr->readers--;
        //读者释放完全 0,释放写信号量
        if (keyMemRwPtr->readers == 0) {
            sem_post(&(keyMemRwPtr->writeSem)); // 释放写者等待
        }
        sem_post(&(keyMemRwPtr->readNumCount));// 释放读者等待
    } else if (RwFlag == 'w') {
        // 读写者互斥
        keyMemRwPtr->writers--;
        if (keyMemRwPtr->writers == 0) {
            sem_post(&(keyMemRwPtr->readSem)); // 释放读者等待
            sem_post(&(keyMemRwPtr->writeSem));
        }
    }
}

void *reader_thread(void *arg) {
    int id = *((int *)arg);
    while (1) {
        rwlock_rdlock();
        printf("Reader %d: Read shared_data = %d\n", id, shared_data);
        rwlock_unlock('r');
        usleep(500000); // Sleep for 500ms
    }
    return NULL;
}

void *writer_thread(void *arg) {
    int id = *((int *)arg);
    while (1) {
        rwlock_wrlock();
        shared_data++;
        printf("Writer %d: Wrote shared_data = %d\n", id, shared_data);
        rwlock_unlock('w');
        usleep(1000000); // Sleep for 1s
    }
    return NULL;
}

int main() {
    setbuf(stdout,NULL);
    memlock_init();

    // 创建多个读者和写者线程
    pthread_t readers[3], writers[2];
    int reader_ids[3] = {1, 2, 3};
    int writer_ids[2] = {1, 2};
    for (int i = 0; i < 3; i++) {
        pthread_create(&readers[i], NULL, reader_thread, &reader_ids[i]);
    }
    for (int i = 0; i < 2; i++) {
        pthread_create(&writers[i], NULL, writer_thread, &writer_ids[i]);
    }

    // 等待线程完成
    for (int i = 0; i < 3; i++) {
        pthread_join(readers[i], NULL);
    }
    for (int i = 0; i < 2; i++) {
        pthread_join(writers[i], NULL);
    }

    // 销毁读写锁
    // ...

    return 0;
}

读写锁

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>

typedef struct __pthread_st {
    pthread_rwlock_t mem_mutex;
    int count;
} PthreadLock_t;

static PthreadLock_t *mptr = NULL;

static int memlock_init()
{
    pthread_rwlockattr_t mattr;
    mptr = mmap(0, sizeof(PthreadLock_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
    if (mptr == MAP_FAILED)
    {
        printf("memlock_init mmap error\n");
        return -1;
    }

    pthread_rwlockattr_init(&mattr);
    pthread_rwlockattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
    pthread_rwlock_init(&(mptr->mem_mutex), &mattr);
    return 0;
}

static void memlock(char RW)
{
    if(RW == 'r'){
        pthread_rwlock_rdlock(&(mptr->mem_mutex));
    }else{
        pthread_rwlock_wrlock(&(mptr->mem_mutex));
    }
}

static void memunlock()
{
    pthread_rwlock_unlock(&(mptr->mem_mutex));
}

void *reader_function(void *arg)
{
    int thread_id = *(int *)arg;
    while (1)
    {
        // Read lock
        memlock('r');
        printf("Reader thread %d: Got read lock, count = %d\n", thread_id, mptr->count);
        // Do some work here...

        // Unlock
        memunlock();

        // Sleep for a while
        usleep(500000);
    }
}

void *writer_function(void *arg)
{
    int thread_id = *(int *)arg;
    while (1)
    {
        // Write lock
        memlock('w');
        printf("Writer thread %d: Got write lock, count = %d\n", thread_id, mptr->count);
        // Do some work here...
        mptr->count ++;

        // Unlock
        memunlock();

        // Sleep for a while
        usleep(1000000);
    }
}

int main()
{
    setbuf(stdout, NULL);
    if (memlock_init() != 0)
    {
        printf("Failed to initialize shared memory and read-write lock.\n");
        return -1;
    }

    const int num_readers = 5;
    const int num_writers = 2;

    pthread_t reader_threads[num_readers];
    pthread_t writer_threads[num_writers];

    // Spawn reader threads
    for (int i = 0; i < num_readers; i++)
    {
        int *thread_id = malloc(sizeof(int));
        *thread_id = i;
        if (pthread_create(&reader_threads[i], NULL, reader_function, thread_id) != 0)
        {
            printf("Failed to create reader thread %d.\n", i);
            return -1;
        }
    }

    // Spawn writer threads
    for (int i = 0; i < num_writers; i++)
    {
        int *thread_id = malloc(sizeof(int));
        *thread_id = i;
        if (pthread_create(&writer_threads[i], NULL, writer_function, thread_id) != 0)
        {
            printf("Failed to create writer thread %d.\n", i);
            return -1;
        }
    }

    // Wait for the threads to finish
    for (int i = 0; i < num_readers; i++)
    {
        pthread_join(reader_threads[i], NULL);
    }

    for (int i = 0; i < num_writers; i++)
    {
        pthread_join(writer_threads[i], NULL);
    }

    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值