|
一、为什么要线程同步
在Linux 多线程编程中,线程同步是一个非常重要的问题。如果线程之间没有正确地同步,就会导致程序出现一些意外的问题,例如:
- 竞态条件(Race Condition):多个线程同时修改同一个共享变量,可能会导致不可预测的结果,因为线程的执行顺序是不确定的。
- 死锁(Deadlock):当两个或多个线程互相等待对方释放资源时,可能会导致死锁,这会导致程序无法继续执行。
- 活锁(Livelock):当多个线程相互响应对方的动作,而没有任何进展时,可能会导致活锁,这也会导致程序无法继续执行。
- 两个人在走路时需要相互让路,两个人都想让对方先通过,但最终还是没有人通过,这就是一种活锁情况
接下来将介绍互斥锁、条件变量、信号量、读写锁这几种线程同步方法,并使用C语言代码示例说明其使用方法。
二、互斥锁
互斥锁是一种用于线程同步的锁,用于保护共享资源。只有拥有该锁的线程才能访问共享资源,其他线程需要等待锁被释放后才能继续执行。
在Linux环境下,我们可以使用pthread库提供的互斥锁函数来实现互斥锁机制。以下是一些常用的互斥锁函数:
函数名描述pthread_mutex_init初始化互斥锁pthread_mutex_lock加锁互斥锁pthread_mutex_trylock尝试加锁互斥锁pthread_mutex_unlock解锁互斥锁pthread_mutex_destroy销毁互斥锁初始化互斥锁
在使用互斥锁之前,需要先初始化互斥锁。pthread_mutex_init函数用于初始化一个互斥锁。函数原型如下:- int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
复制代码 其中,mutex参数是一个指向pthread_mutex_t结构体的指针,用于指定要初始化的互斥锁;attr参数是一个指向pthread_mutexattr_t结构体的指针,用于指定互斥锁的属性,通常设置为NULL。
以下是一个初始化互斥锁的例子:- #include <pthread.h>
- pthread_mutex_t mutex;
- int main()
- {
- // 初始化互斥锁
- pthread_mutex_init(&mutex, NULL);
-
- // ...
-
- // 销毁互斥锁
- pthread_mutex_destroy(&mutex);
-
- return 0;
- }
复制代码 加锁互斥锁
加锁互斥锁用于保证同一时刻只有一个线程能够访问共享资源。pthread_mutex_lock函数用于加锁一个互斥锁。函数原型如下:- int pthread_mutex_lock(pthread_mutex_t *mutex);
复制代码 其中,mutex参数是一个指向pthread_mutex_t结构体的指针,用于指定要加锁的互斥锁。
以下是一个加锁互斥锁的例子:- #include <pthread.h>
- pthread_mutex_t mutex;
- void* thread_func(void* arg)
- {
- // 加锁互斥锁
- pthread_mutex_lock(&mutex);
-
- // 访问共享资源
- // ...
-
- // 解锁互斥锁
- pthread_mutex_unlock(&mutex);
-
- return NULL;
- }
- int main()
- {
- // 初始化互斥锁
- pthread_mutex_init(&mutex, NULL);
-
- // 创建线程
- pthread_t tid;
- pthread_create(&tid, NULL, thread_func, NULL);
-
- // ...
-
- // 等待线程结束
- pthread_join(tid, NULL);
-
- // 销毁互斥锁
- pthread_mutex_destroy(&mutex);
-
- return 0;
- }
复制代码 尝试加锁互斥锁
尝试加锁互斥锁与加锁互斥锁的主要区别在于,如果互斥锁已经被其他线程锁定了,尝试加锁互斥锁将不会阻塞当前线程,而是会立即返回一个错误代码。函数原型如下:- int pthread_mutex_trylock(pthread_mutex_t *mutex);
复制代码 其中,mutex参数是一个指向pthread_mutex_t结构体的指针,用于指定要尝试加锁的互斥锁。
以下是一个尝试加锁互斥锁的例子:- #include <pthread.h>
- pthread_mutex_t mutex;
- void* thread_func(void* arg)
- {
- // 尝试加锁互斥锁
- int ret = pthread_mutex_trylock(&mutex);
- if (ret == 0) {
- // 访问共享资源
- // ...
-
- // 解锁互斥锁
- pthread_mutex_unlock(&mutex);
- } else {
- // 互斥锁已经被其他线程锁定了
- // ...
- }
-
- return NULL;
- }
- int main()
- {
- // 初始化互斥锁
- pthread_mutex_init(&mutex, NULL);
-
- // 创建线程
- pthread_t tid;
- pthread_create(&tid, NULL, thread_func, NULL);
-
- // ...
-
- // 等待线程结束
- pthread_join(tid, NULL);
-
- // 销毁互斥锁
- pthread_mutex_destroy(&mutex);
-
- return 0;
- }
复制代码 解锁互斥锁
解锁互斥锁用于释放已经锁定的互斥锁。pthread_mutex_unlock函数用于解锁一个互斥锁。函数原型如下:- int pthread_mutex_unlock(pthread_mutex_t *mutex);
复制代码 其中,mutex参数是一个指向pthread_mutex_t结构体的指针,用于指定要解锁的互斥锁。
以下是一个解锁互斥锁的例子:- #include <pthread.h>
- pthread_mutex_t mutex;
- void* thread_func(void* arg)
- {
- // 加锁互斥锁
- pthread_mutex_lock(&mutex);
-
- // 访问共享资源
- //
- // 解锁互斥锁
- pthread_mutex_unlock(&mutex);
- return NULL;
- }
复制代码 销毁互斥锁
在不再需要使用互斥锁时,需要将互斥锁销毁。pthread_mutex_destroy函数用于销毁一个互斥锁。函数原型如下:- int pthread_mutex_destroy(pthread_mutex_t *mutex);
复制代码 其中,mutex参数是一个指向pthread_mutex_t结构体的指针,用于指定要销毁的互斥锁。
以下是一个销毁互斥锁的例子:- #include <pthread.h>
- pthread_mutex_t mutex;
- int main()
- {
- // 初始化互斥锁
- pthread_mutex_init(&mutex, NULL);
-
- // ...
-
- // 销毁互斥锁
- pthread_mutex_destroy(&mutex);
-
- return 0;
- }
复制代码 示例程序
下面是一个简单的示例程序,演示了如何使用互斥锁来同步两个线程的访问。- #include <stdio.h>
- #include <stdlib.h>
- #include <pthread.h>
- pthread_mutex_t mutex;
- int shared_data = 0;
- void *thread_func(void *arg)
- {
- int i;
- for (i = 0; i < 1000000; i++) {
- pthread_mutex_lock(&mutex);
- shared_data++;
- pthread_mutex_unlock(&mutex);
- }
- return NULL;
- }
- int main()
- {
- pthread_t thread1, thread2;
- pthread_mutex_init(&mutex, NULL);
- pthread_create(&thread1, NULL, thread_func, NULL);
- pthread_create(&thread2, NULL, thread_func, NULL);
- pthread_join(thread1, NULL);
- pthread_join(thread2, NULL);
- pthread_mutex_destroy(&mutex);
- printf("Shared data: %d\n", shared_data);
- return 0;
- }
复制代码 在这个程序中,thread_func函数是两个线程执行的函数,它会对shared_data变量进行1000000次加一操作。
为了确保多个线程不会同时访问shared_data变量,我们使用了一个互斥锁。当一个线程要访问shared_data变量时,它会调用pthread_mutex_lock函数来加锁。如果锁已经被其他线程持有,那么这个线程就会被阻塞,直到锁被释放为止。当线程完成对shared_data变量的操作后,它会调用pthread_mutex_unlock函数来释放锁。
在这个程序执行完毕后,我们可以通过打印shared_data变量的值来检查程序是否正确地同步了两个线程的访问。如果程序正确地同步了线程的访问,那么shared_data变量的值应该是2000000。
来源:https://www.cnblogs.com/Wayne123/p/17278046.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|