您的位置:首页 > 财经 > 金融 > 网页设计作品源文件_家乐福购物卡官网_seo的培训班_成长电影在线观看免费

网页设计作品源文件_家乐福购物卡官网_seo的培训班_成长电影在线观看免费

2025/1/3 6:55:53 来源:https://blog.csdn.net/m0_52043808/article/details/144833634  浏览:    关键词:网页设计作品源文件_家乐福购物卡官网_seo的培训班_成长电影在线观看免费
网页设计作品源文件_家乐福购物卡官网_seo的培训班_成长电影在线观看免费

读写锁是一种同步原语,用于管理对共享资源或临界区的访问,允许多个线程同时读取数据(共享锁),但当有线程需要写入数据时(独占锁),则要求排他性的访问,即不允许其他任何线程(无论是读还是写)同时访问该数据。这种机制在读操作远多于写操作的应用场景中,能显著提高并发性能。

读写锁的工作原理

(1)共享锁(读锁):当没有线程持有写锁时,任意数量的线程可以同时持有读锁。持有读锁的线程只能进行读操作,不能修改共享资源。

(2)独占锁(写锁):写锁是排他的,即当一个线程持有写锁时,其他所有试图获取读锁或写锁的线程都会被阻塞。持有写锁的线程既可以读取也可以修改共享资源。

锁转换:从读锁到写锁的转换通常不是原子操作,因为这可能涉及到释放所有当前的读锁,并确保在此期间没有新的读锁被获取。同样,从写锁到读锁的转换也需要特别小心,以避免竞态条件。

应用场景

读写锁最适合用于那些读操作频繁而写操作较少的情况。例如,在缓存系统、数据库查询等场景中,大多数情况下都是查询(读)数据,只有少数情况会更新(写)数据。使用读写锁可以提高这些应用的并发处理能力,因为它允许多个读线程同时访问共享资源,而不像互斥锁那样会阻塞所有的读线程。

读写锁(Read-Write Lock)在POSIX线程(pthread)库中通过pthread_rwlock_t类型来表示。为了管理对共享资源的访问,提供了几个函数用于初始化、获取和释放读写锁。

初始化读写锁

静态分配的pthread_rwlock_t类型的变量可以通过赋值PTHREAD_RWLOCK_INITIALIZER进行初始化。对于动态分配的读写锁,可以使用pthread_rwlock_init函数进行初始化,并且可以在初始化时指定属性。

pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

使用初始化函数:

#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
获取读写锁

获取读锁 pthread_rwlock_rdlock:阻塞调用直到成功获取读锁

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

pthread_rwlock_tryrdlock:尝试获取读锁,如果不能立即获取,则返回EBUSY而不阻塞。

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

获取写锁

pthread_rwlock_wrlock:阻塞调用直到成功获取写锁。

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

pthread_rwlock_trywrlock:尝试获取写锁,如果不能立即获取,则返回EBUSY而不阻塞。

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

所有上述获取锁的函数均返回0表示成功,返回正值表示错误代码(例如EBUSY表示忙,无法立即获取锁)。

释放读写锁

pthread_rwlock_unlock:释放一个当前持有的读锁或写锁。如果该锁被多个读者持有,则只减少持锁计数;如果该锁是写锁,则完全释放它。

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

此函数也返回0表示成功,返回正值表示错误代码。

读写锁属性

读写锁(Read-Write Lock)不仅可以通过静态初始化的方式设置,还可以通过动态初始化和属性配置来满足不同的需求。

动态初始化与摧毁

初始化

要动态地初始化一个读写锁,可以使用pthread_rwlock_init函数。如果第二个参数attr是空指针,则使用默认属性。

#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);

摧毁

当不再需要某个读写锁时,应调用pthread_rwlock_destroy来摧毁它,以便释放相关的资源。

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

这两个函数均返回0表示成功,返回正值表示错误代码。

属性管理

属性初始化与摧毁

要为读写锁设置非默认属性,首先需要初始化一个属性对象pthread_rwlockattr_t,然后可以在初始化后修改其属性。

int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);

同样,这些函数也返回0表示成功,返回正值表示错误代码。

设置与获取进程共享属性

当前唯一定义的属性是PTHREAD_PROCESS_SHARED,它决定了读写锁是在单个进程内的线程间共享(PTHREAD_PROCESS_PRIVATE),还是在不同进程间共享(PTHREAD_PROCESS_SHARED)。

设置属性

int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int value);

value应该设置为PTHREAD_PROCESS_PRIVATE或PTHREAD_PROCESS_SHARED。

获取属性:

int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *valptr);

该函数将当前属性值存储到由valptr指向的变量中。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
int main() {pthread_rwlock_t rwlock;pthread_rwlockattr_t attr;// 初始化属性对象if (pthread_rwlockattr_init(&attr) != 0) {perror("Failed to initialize rwlock attributes");exit(EXIT_FAILURE);}// 设置属性为进程间共享if (pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) != 0) {perror("Failed to set pshared attribute");pthread_rwlockattr_destroy(&attr);exit(EXIT_FAILURE);}// 使用指定的属性初始化读写锁if (pthread_rwlock_init(&rwlock, &attr) != 0) {perror("Failed to initialize rwlock");pthread_rwlockattr_destroy(&attr);exit(EXIT_FAILURE);}// 销毁属性对象if (pthread_rwlockattr_destroy(&attr) != 0) {perror("Failed to destroy rwlock attributes");pthread_rwlock_destroy(&rwlock);exit(EXIT_FAILURE);}// 使用读写锁...// 最终摧毁读写锁if (pthread_rwlock_destroy(&rwlock) != 0) {perror("Failed to destroy rwlock");exit(EXIT_FAILURE);}return 0;
}
使用互斥锁和条件变量实现读写锁

👋结合引用计数相关的知识点(shared_ptr,(python,java,)垃圾回收,inode节点)

为了实现读写锁(Read-Write Lock)并优先考虑等待的写入者,可以使用互斥锁(pthread_mutex_t)和条件变量(pthread_cond_t)。

数据结构定义

首先定义pthread_rwlock_t结构体来表示读写锁。这个结构体包含了用于同步的互斥锁、用于等待的条件变量、标志字段以及计数器。

#ifndef PTHREAD_RWLOCK_H
#define PTHREAD_RWLOCK_H
#include <pthread.h>
typedef struct {pthread_mutex_t rw_mutex;      /* 互斥锁 */pthread_cond_t rw_condreaders; /* 读者等待条件变量 */pthread_cond_t rw_condwriters; /* 写者等待条件变量 */int rw_magic;                  /* 错误检查标志 */int rw_nwaitreaders;           /* 等待的读者数量 */int rw_nwaitwriters;           /* 等待的写者数量 */int rw_refcount;               /* 引用计数:-1为写锁,>0为读锁数量 */
} pthread_rwlock_t;
#define RW_MAGIC 0x19283746
#define PTHREAD_RWLOCK_INITIALIZER \
{  \PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, RW_MAGIC, 0, 0, 0 \
}
typedef int pthread_rwlockattr_t;
#endif /* PTHREAD_RWLOCK_H */

初始化与摧毁

初始化:动态初始化一个读写锁,并设置默认属性。

int pthread_rwlock_init(pthread_rwlock_t *rw, pthread_rwlockattr_t *attr) {if (attr != NULL)return EINVAL; // 不支持非空属性if (pthread_mutex_init(&rw->rw_mutex, NULL) != 0 ||pthread_cond_init(&rw->rw_condreaders, NULL) != 0 ||pthread_cond_init(&rw->rw_condwriters, NULL) != 0) {// 处理错误情况,确保已初始化的对象被正确摧毁pthread_cond_destroy(&rw->rw_condreaders);pthread_cond_destroy(&rw->rw_condwriters);pthread_mutex_destroy(&rw->rw_mutex);return errno;}rw->rw_nwaitreaders = 0;rw->rw_nwaitwriters = 0;rw->rw_refcount = 0;rw->rw_magic = RW_MAGIC;return 0;
}

摧毁

在所有线程不再持有或试图持有某个读写锁时摧毁它。

int pthread_rwlock_destroy(pthread_rwlock_t *rw) {if (rw->rw_magic != RW_MAGIC)return EINVAL;if (rw->rw_refcount != 0 || rw->rw_nwaitreaders != 0 || rw->rw_nwaitwriters != 0)return EBUSY;pthread_mutex_destroy(&rw->rw_mutex);pthread_cond_destroy(&rw->rw_condreaders);pthread_cond_destroy(&rw->rw_condwriters);rw->rw_magic = 0;return 0;
}

获取与释放锁

获取读锁

int pthread_rwlock_rdlock(pthread_rwlock_t *rw) {if (rw->rw_magic != RW_MAGIC)return EINVAL;if (pthread_mutex_lock(&rw->rw_mutex) != 0)return errno;while (rw->rw_refcount < 0 || rw->rw_nwaitwriters > 0) {rw->rw_nwaitreaders++;int result = pthread_cond_wait(&rw->rw_condreaders, &rw->rw_mutex);rw->rw_nwaitreaders--;if (result != 0)break;}if (errno == 0)rw->rw_refcount++;pthread_mutex_unlock(&rw->rw_mutex);return errno;
}

尝试获取读锁(非阻塞)

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rw) {if (rw->rw_magic != RW_MAGIC)return EINVAL;if (pthread_mutex_lock(&rw->rw_mutex) != 0)return errno;if (rw->rw_refcount < 0 || rw->rw_nwaitwriters > 0)errno = EBUSY;elserw->rw_refcount++;pthread_mutex_unlock(&rw->rw_mutex);return errno;
}

获取写锁

int pthread_rwlock_wrlock(pthread_rwlock_t *rw) {if (rw->rw_magic != RW_MAGIC)return EINVAL;if (pthread_mutex_lock(&rw->rw_mutex) != 0)return errno;while (rw->rw_refcount != 0) {rw->rw_nwaitwriters++;int result = pthread_cond_wait(&rw->rw_condwriters, &rw->rw_mutex);rw->rw_nwaitwriters--;if (result != 0)break;}if (errno == 0)rw->rw_refcount = -1;pthread_mutex_unlock(&rw->rw_mutex);return errno;
}

尝试获取写锁(非阻塞)

int pthread_rwlock_trywrlock(pthread_rwlock_t *rw) {if (rw->rw_magic != RW_MAGIC) return EINVAL;if (pthread_mutex_lock(&rw->rw_mutex) != 0) return errno;if (rw->rw_refcount != 0)errno = EBUSY;elserw->rw_refcount = -1;pthread_mutex_unlock(&rw->rw_mutex);return errno;
}

释放锁

int pthread_rwlock_unlock(pthread_rwlock_t *rw) {if (rw->rw_magic != RW_MAGIC)return EINVAL;if (pthread_mutex_lock(&rw->rw_mutex) != 0)return errno;if (rw->rw_refcount > 0)rw->rw_refcount--; // 释放读锁else if (rw->rw_refcount == -1)rw->rw_refcount = 0; // 释放写锁elseerr_dump("rw_refcount = %d", rw->rw_refcount);// 给等待的写者优先权if (rw->rw_nwaitwriters > 0 && rw->rw_refcount == 0)pthread_cond_signal(&rw->rw_condwriters);else if (rw->rw_nwaitreaders > 0)pthread_cond_broadcast(&rw->rw_condreaders);pthread_mutex_unlock(&rw->rw_mutex);return 0;
}

注意事项

(1)优先级反转:该实现优先考虑等待的写入者,以防止写入者饥饿。

(2)取消安全性:如果调用线程在pthread_cond_wait中被取消,可能会导致资源泄漏问题。实际应用中需要处理这种情况。

(3)线程安全:所有对pthread_rwlock_t结构体成员的操作都必须在持有rw_mutex的情况下进行,以保证线程安全。

线程取消

👋结合C++ RAII和java的什么机制讲。

线程取消是POSIX线程库提供的一种机制,允许一个线程被同一进程内的其他线程所取消。当一个线程被取消时,它会立即终止其执行,并可以触发清理处理程序来恢复资源或状态。

通过调用pthread_cancel函数可以请求取消另一个线程。

#include <pthread.h>
int pthread_cancel(pthread_t thread);

thread是要取消的线程的线程ID。成功时返回0,失败时返回正值表示错误代码。

取消状态与类型

每个线程都有一个取消状态(PTHREAD_CANCEL_ENABLE或PTHREAD_CANCEL_DISABLE)和取消类型(PTHREAD_CANCEL_DEFERRED或PTHREAD_CANCEL_ASYNCHRONOUS)。可以通过pthread_setcancelstate和pthread_setcanceltype设置这些属性。

int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);

默认情况下,线程处于PTHREAD_CANCEL_ENABLE状态和PTHREAD_CANCEL_DEFERRED类型,意味着它们可以被取消,但在取消点之前不会立即响应取消请求。

清理处理程序

为了确保在取消线程时能够正确释放资源或恢复状态,可以安装清理处理程序。这些处理程序在线程被取消、自愿退出(如调用pthread_exit或从线程起始函数返回)时自动调用。

安装和移除清理处理程序

使用pthread_cleanup_push和pthread_cleanup_pop宏来安装和移除清理处理程序。

void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);

pthread_cleanup_push将指定的清理函数压入当前线程的清理栈中。pthread_cleanup_pop从清理栈中弹出位于栈顶的清理函数,并根据execute参数决定是否调用该函数(非零值表示调用)。线程中使用清理处理程序来确保互斥锁被正确释放:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void cleanup_handler(void *arg) {printf("Cleanup handler called\n");pthread_mutex_unlock((pthread_mutex_t *)arg);
}
void *thread_function(void *arg) {pthread_cleanup_push(cleanup_handler, (void *)&mutex);if (pthread_mutex_lock(&mutex) != 0) {perror("Failed to lock mutex");pthread_cleanup_pop(0); // Remove cleanup handler without executing itreturn NULL;}// 模拟长时间操作,可能会被取消sleep(10);pthread_cleanup_pop(1); // Remove and execute cleanup handlerreturn NULL;
}
int main() {pthread_t thread;if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {perror("Failed to create thread");exit(EXIT_FAILURE);}sleep(1); // 让新线程运行一会儿// 请求取消线程if (pthread_cancel(thread) != 0) {perror("Failed to cancel thread");exit(EXIT_FAILURE);}if (pthread_join(thread, NULL) != 0) {perror("Failed to join thread");exit(EXIT_FAILURE);}pthread_mutex_destroy(&mutex);return 0;
}

注意事项

(1)取消点:只有在线程到达取消点时,取消请求才会生效。常见的取消点包括阻塞系统调用、某些POSIX线程库函数等。

(2)清理处理程序的作用范围:pthread_cleanup_push和pthread_cleanup_pop必须成对出现,通常在同一作用域内使用。

(3)避免死锁:确保清理处理程序不会导致新的资源竞争或死锁情况,例如不要在清理处理程序中尝试获取已经持有的锁。

(4)线程安全:所有涉及共享资源的操作都应考虑线程安全性,尤其是在处理取消时。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com