首页 > 系统相关 >Linux线程同步必知,常用方法揭秘!

Linux线程同步必知,常用方法揭秘!

时间:2023-04-01 09:03:35浏览次数:39  
标签:必知 cond Linux 互斥 mutex pthread 线程 NULL

一、为什么要线程同步

在Linux 多线程编程中,线程同步是一个非常重要的问题。如果线程之间没有正确地同步,就会导致程序出现一些意外的问题,例如:

  1. 竞态条件(Race Condition):多个线程同时修改同一个共享变量,可能会导致不可预测的结果,因为线程的执行顺序是不确定的。
  2. 死锁(Deadlock):当两个或多个线程互相等待对方释放资源时,可能会导致死锁,这会导致程序无法继续执行。
  3. 活锁(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。

标签:必知,cond,Linux,互斥,mutex,pthread,线程,NULL
From: https://www.cnblogs.com/Wayne123/p/17278046.html

相关文章

  • Linux:常用命令有哪些?
    查看文件查看文件属性:file 文件名查看内容全部内容:cat-n(可选,显示行号)文件名分页查看:less文件名文件尾部:tail文件名头部:head文件名新建文件夹mkdir......
  • Linux设备文件三大结构:inode,file,file_operations
    structinodeLinux中一切皆文件,当我们在Linux中创建一个文件时,就会在相应的文件系统创建一个inode与之对应,文件实体和文件的inode是一一对应的,创建好一个inode会存在存储器中,第一次open就会将inode在内存中有一个备份,同一个文件被多次打开并不会产生多个inode,当所有被打开的文件......
  • Redhat/CentOS Linux 系统进入单用户模式
    Redhat/CentOSLinux系统进入单用户模式以CentOS7.9和Redhat8.2为例进行操作,因为CentOS是Redhat的发行版,所以同版本号界面和操作是一样的。CentOS7.9 开机在grub引导界面时,按下e键进入编辑模式: 找到linux16这一行,在行末添加rd.break(注意这里是一整行),使用Ct......
  • RockyLinux9配置网络
    编辑配置文件vim/etc/sysconfig/network-scripts/ifcfg-enp0s3TYPE=EthernetPROXY_METHOD=noneBROWSER_ONLY=noBOOTPROTO=noneDEFROUTE=yesIPV4_FAILURE_FATAL=noIPV6INIT=noNAME=enp0s3DEVICE=enp0s3ONBOOT=yesIPADDR=192.168.1.110PREFIX=24GATEWAY=192.168.1.1D......
  • 四个常见的Linux面试问题
    刚毕业要找工作了,只要是你找工作就会有面试这个环节,那么在面试环节中,有哪些注意事项值得我的关注呢?特别是专业技术岗位,这样的岗位询问一般都是在职的工程师,如何在面试环节更好地理解面试官的问题,我们一起往下看吧。在学校学习也好,在培训机构或者网络在线学习也好,无论是通过那种途......
  • 【webserver 前置知识 02】Linux网络编程入门其一
    网络结构模式C/S结构服务器-客户机,即Client-Server(C/S)结构。C/S结构通常采取两层结构。服务器负责数据的管理,客户机负责完成与用户的交互任务。客户机是因特网上访问别人信息的机器,服务器则是提供信息供人访问的计算机。在C/S结构中,应用程序分为两部分:服务器部分和客户......
  • 用飞书账号登录web应用、Linux服务器
    某初创型的科技公司拥有5、6个web应用,采用飞书作为移动办公沟通协作工具。为提高办公效率及运维效率,公司想用飞书账号作为身份源,登录web应用及Linux服务器。视该公司部署方式而定(本地化部署还是采用SaaS服务),宁盾有对应的产品及解决方案:宁盾目录服务或云身份目录平台。解决思路是:将......
  • linux下的vim使用教程!从零基础到入门!
    linux下的vim使用教程!从零基础到入门!vim的介绍!Vim是一个类似于vi的著名的功能强大、高度可定制的文本编辑器,在Vi的基础上改进和增加了很多特性vim是一种多模式的编译器!也是在linux下进行编程的一种常用的编辑器!因为其很高的上手难度,也往往让很多新人看了望而却步!今天我将详细的......
  • linux ftp服务器报错:425 Data Connection Failed.的解决方法
    原先我写的脚本:然后会出现450错误  修改后的脚本: 再操作前,增加passive一条语句就解决了。参考博客:https://www.codenong.com/cs106853176/    ......
  • 关于linux环境下配置c/c++程序的编译器
    第一步:切换root用户     命令为:suroot然后输入密码即可第二步:输入命令  yum installgcc 和 yuminstall g++  第三步:通过查找路径来检查是否安装成功  whichgcc和 whichg++......