代码示例创建了多个读者线程和一个写者线程来访问共享资源(这里是一个文件)。在读者线程中,使用了文件I/O函数打开文件、映射文件到内存,并对文件内容进行了读取。在写者线程中,也使用了文件I/O函数打开文件、映射文件到内存,并对文件内容进行了写入。完整代码如下,简洁易懂。
#include
#include
#include
#include
#include
#include
#include
#include
// 定义读写锁结构体
typedef struct
{
pthread_mutex_t mutex; // 互斥锁,保护对读写锁的访问
pthread_cond_t read_cond; // 读条件变量,用于同步读操作
pthread_cond_t write_cond; // 写条件变量,用于同步写操作
int readers; // 当前读者的数量
int writer; // 当前写者的数量(0或1)
} rwlock_t;
// 初始化读写锁
void rwlock_init(rwlock_t *lock)
{
lock->readers = 0;
lock->writer = 0;
pthread_mutex_init(&lock->mutex, NULL);
pthread_cond_init(&lock->read_cond, NULL);
pthread_cond_init(&lock->write_cond, NULL);
}
// 上读锁
void rwlock_read_lock(rwlock_t *lock)
{
pthread_mutex_lock(&lock->mutex);
while (lock->writer > 0)
{ // 若有写者存在,等待
pthread_cond_wait(&lock->read_cond, &lock->mutex);
}
lock->readers++; // 读者数量增加
pthread_mutex_unlock(&lock->mutex);
}
// 解读锁
void rwlock_read_unlock(rwlock_t *lock)
{
pthread_mutex_lock(&lock->mutex);
lock->readers--; // 读者数量减少
if (lock->readers == 0)
{ // 最后一个读者解锁时唤醒写者
pthread_cond_signal(&lock->write_cond);
}
pthread_mutex_unlock(&lock->mutex);
}
// 上写锁
void rwlock_write_lock(rwlock_t *lock)
{
pthread_mutex_lock(&lock->mutex);
while (lock->readers > 0 || lock->writer > 0)
{ // 若有读者或写者存在,等待
pthread_cond_wait(&lock->write_cond, &lock->mutex);
}
lock->writer = 1; // 写者存在
pthread_mutex_unlock(&lock->mutex);
}
// 解写锁
void rwlock_write_unlock(rwlock_t *lock)
{
pthread_mutex_lock(&lock->mutex);
lock->writer = 0; // 写者不存在
if (lock->readers > 0)
{ // 唤醒所有读者
pthread_cond_broadcast(&lock->read_cond);
}
else
{ // 或者唤醒一个写者
pthread_cond_signal(&lock->write_cond);
}
pthread_mutex_unlock(&lock->mutex);
}
// 示例使用读写锁的线程函数
void *reader_thread(void *arg)
{
rwlock_t *lock = (rwlock_t *)arg;
printf("Reader thread start.\n");
rwlock_read_lock(lock);
printf("Reading data...\n");
// 进行读操作
int fd = open("./shmem.c", O_RDONLY);
if (fd == -1)
{
perror("Error opening file");
return EXIT_FAILURE;
}
unsigned char *addr = (unsigned char *)mmap(NULL, 753, PROT_READ, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
perror("Error mapping file");
close(fd);
return EXIT_FAILURE;
}
// Print the content byte by byte
for (int i = 0; i < 753; ++i)
{
printf("%c", addr[i]);
}
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
if (munmap(addr, 753) == -1)
{
perror("Error unmapping file");
close(fd);
return EXIT_FAILURE;
}
close(fd);
rwlock_read_unlock(lock);
printf("Reader thread end.\n");
return NULL;
}
void *writer_thread(void *arg)
{
rwlock_t *lock = (rwlock_t *)arg;
printf("Writer thread start.\n");
rwlock_write_lock(lock);
printf("Writing data...\n");
// 进行写操作
int fd = open("./shmem.c", O_RDWR);
if (fd == -1)
{
perror("Error opening file");
return NULL;
}
unsigned char *addr = (unsigned char *)mmap(NULL, 753, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
perror("Error mapping file");
close(fd);
return NULL;
}
// Print the content byte by byte
for (int i = 0; i < 753; i++)
{
addr[i] = 'm';
}
if (munmap(addr, 753) == -1)
{
perror("Error unmapping file");
close(fd);
return NULL;
}
close(fd);
rwlock_write_unlock(lock);
printf("Writer thread end.\n");
return NULL;
}
int main()
{
pthread_t readers[3];
pthread_t writer;
rwlock_t lock;
rwlock_init(&lock);
for (int i = 0; i < 3; i++)
{
pthread_create(&readers[i], NULL, reader_thread, &lock);
}
pthread_create(&writer, NULL, writer_thread, &lock);
for (int i = 0; i < 3; i++)
{
pthread_join(readers[i], NULL);
}
pthread_join(writer, NULL);
return 0;
}
在C语言中,没有像其他编程语言中的原生支持的try-catch
语句。但你可以使用setjmp
和longjmp
函数来实现类似的错误处理机制。
未完待续。。。。。。。。。。。。下面是仅是一种简单的实现示例
下面是一个简单的示例代码,演示了如何使用setjmp
和longjmp
来实现try-catch
风格的错误处理:
#include
#include
jmp_buf jmp_buffer;
void divide(int a, int b)
{
if (b == 0)
{
printf("Error: Division by zero\n");
longjmp(jmp_buffer, 1);
}
else
{
int result = a / b;
printf("Result: %d\n", result);
}
}
int main()
{
if (setjmp(jmp_buffer) == 0)
{
// 这里是try块
divide(10, 0);
divide(20, 5);
}
else
{
// 这里是catch块
printf("Exception caught\n");
}
return 0;
}
在上面的示例代码中,setjmp
用于设置一个跳转点,并返回0。然后,divide
函数被调用,如果除数为0,则会调用longjmp
跳转回setjmp
所设置的跳转点,并返回非零值。在setjmp
之后的代码就相当于try
块,如果发生错误,则会在longjmp
处跳转到setjmp
之后,并执行else
块作为catch
块来处理异常。
需要注意的是,setjmp
和longjmp
的使用需要非常小心,因为它们会绕过正常的函数调用和返回机制,可能导致资源泄漏或非预期的行为。此外,setjmp
和longjmp
只能用于跳出当前的函数范围,不能跨越多个函数。在实际使用中,请务必谨慎并遵循最佳的错误处理实践。