Linux 多线程同步机制(上)

这篇具有很好参考价值的文章主要介绍了Linux 多线程同步机制(上)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言


一、线程同步

在多线程环境下,多个线程可以并发地执行,访问共享资源(如内存变量、文件、网络连接  等)。
这可能导致 数据不一致性, 死锁, 竞争条件等 问题。
为了解决这些问题,需要使用同步机制来确保线程间的协作和互斥访问共享资源。

“同步” 的目的 是为了避免数据的混乱,解决与时间有关的错误。实际上,不仅线程需要同步,进程间,信号间等等都需要同步机制。

线程同步,指一个线程发出某一功能调用时,在没有得到结果之前,该调用不返回。同时 其他线程为保证数据的一致性,不能调用该功能。

二、互斥量 mutex

互斥锁(Mutex,全称为 Mutual Exclusion)是一种常用的同步机制,用于保护共享资源免受多个线程同时访问和修改的影响。互斥锁提供了一种互斥访问的机制,同一时间只允许一个线程获取锁并访问被保护的资源。

每个线程在对资源操作前都尝试进行先加锁,成功加锁才能操作,操作结束解锁。
资源还是共享的,线程也还是竞争的。
但 通过 “锁” 就将资源的访问变成互斥操作,而后与时间有关的错误也就不会再产生了。

1. 互斥锁的基本操作包括两个关键操作:

  • 加锁(Lock):线程通过申请互斥锁来获取对共享资源的访问权。如果互斥锁当前未被其他线程获取,线程成功获得锁然后进入临界区(Critical Section),可以访问共享资源。如果互斥锁已经被其他线程获取,申请锁的线程将被阻塞,直到锁被释放。

  • 解锁(Unlock):线程在完成对共享资源的访问之后,释放互斥锁,使得其他线程可以申请并获取锁。

2. 互斥锁的主要应用函数 :

pthread_mutex_init: 用于初始化互斥锁变量。
pthread_mutex_destroy: 用于销毁互斥锁对象。
pthread_mutex_lock: 用于加锁,如果互斥锁已被其他线程占用,则当前线程阻塞。
pthread_mutex_trylock: 尝试加锁,如果互斥锁已被其他线程占用,则返回一个失败状态而不阻塞线程。
pthread_mutex_unlock: 用于解锁,释放互斥锁使其他线程可以获取。

3. 初始化线程锁 :
有两种方式可以对互斥锁进行初始化:静态初始化和动态初始化。

  • 静态初始化: 是在定义互斥锁变量时直接进行初始化,不需要调用特定的初始化函数。
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    PTHREAD_MUTEX_INITIALIZER 是一个宏,用于静态初始化互斥锁变量。
  • 动态初始化:动态初始化是在运行时使用初始化函数对互斥锁进行初始化。
    pthread_mutex_init(&mutex, NULL);

4. 示例代码
在下面代码中,main 函数中有一个主线程 打印小写字母,my_thread 为 子线程 打印 大写字母。两个线程通过互斥锁来访问 共享资源。

#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>

pthread_mutex_t lock;							// 创建 互斥锁

void *my_thread(void *arg)
{
	srand(time(NULL));							// 设置随机种子
	
	while(1)
	{
		pthread_mutex_lock(&lock);
		printf("ABC ");
		sleep(rand() % 3);
		printf("XYZ\n");

		pthread_mutex_unlock(&lock);
		sleep(rand() % 3);							// 休眠随机秒,释放cpu资源
	}
	
	pthread_exit(NULL);
}


int main(void)
{
	pthread_t tid;
	int ret;

	srand(time(NULL));									// 设置随机种子

	ret = pthread_mutex_init(&lock,  NULL);				// 初始化互斥锁
	if(ret != 0)
	{
		printf("pthread_mutex_init err\n");
	}

	ret = pthread_create(&tid, NULL, my_thread, NULL);
	if(ret != 0)
	{
		printf("pthread_create err\n");
	}

	while(1)
	{
		pthread_mutex_lock(&lock);
		printf("abc ");
		sleep(rand() % 3);
		printf("xyz\n");

		pthread_mutex_unlock(&lock);
		sleep(rand() % 3);
	}

	pthread_mutex_destroy(&lock);			  	// 销毁 互斥锁

	pthread_join(tid,NULL);				  		// 等待回收线程,获取回收状态

	return 0;
}

注意 :
锁粒度(Lock Granularity):锁的粒度应该尽可能小,以避免锁定过长时间,从而降低了并发性能。

三、死锁

死锁产生的原因:死锁是指多个线程或进程因为彼此相互等待对方所持有的资源而无法继续执行的状态。

解决:

  1. 使用资源的有序性:通过规定线程获取资源的顺序,避免出现循环等待的情况。例如,可以约定所有线程按照一定的顺序获取资源,从而避免死锁的发生。

如果下面两个线程 获取资源的顺序是相反的,则可能会产生死锁。可以将 线程 B 先获取 m1锁,再获取 m2锁。
Linux 多线程同步机制(上),linux,linux,java,数据库,多线程,互斥量mutex
以下面代码的方式获取锁,不会存在死锁风险。文章来源地址https://www.toymoban.com/news/detail-684682.html

#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;

void *my_thread1(void *arg)
{
	pthread_mutex_lock(&lock1);
	printf("my_thread1 : begin\n");

	pthread_mutex_lock(&lock2);
	printf("my_thread1 : end\n");

	pthread_mutex_unlock(&lock2);
	pthread_mutex_unlock(&lock1);
	
	pthread_exit(NULL);
}

void *my_thread2(void *arg)
{
	pthread_mutex_lock(&lock1);
	printf("my_thread2 : begin\n");

	pthread_mutex_lock(&lock2);
	printf("my_thread2 : end\n");

	pthread_mutex_unlock(&lock2);
	pthread_mutex_unlock(&lock1);
	
	pthread_exit(NULL);
}

int main(void)
{
	pthread_t tid1,tid2;
	int ret;

	ret = pthread_create(&tid1, NULL, my_thread1, NULL);
	if(ret != 0)
	{
		printf("pthread1_create err\n");
	}

	ret = pthread_create(&tid2, NULL, my_thread2, NULL);
	if(ret != 0)
	{
		printf("pthread2_create err\n");
	}

	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);

	return 0;
}
  1. 设置超时机制:在请求资源时,设置一个超时时间,在超过该时间后如果仍未获得资源,则放弃等待,释放已经获取的资源,避免长时间的死锁等待。

总结

到了这里,关于Linux 多线程同步机制(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java springboot架构 自定义注解保存项目业务日志,使用线程池保存到数据库

    目录 1:pom.xml依赖 2:注解类样例 3:枚举类 4:具体处理方法类 5:线程池类 1:pom.xml依赖 2:注解类样例 3:枚举类 4:具体处理方法类 5:线程池类

    2024年02月15日
    浏览(50)
  • Linux和windows进程同步与线程同步那些事儿(三): Linux线程同步详解示例

    Linux和windows进程同步与线程同步那些事儿(一) Linux和windows进程同步与线程同步那些事儿(二): windows线程同步详解示例 Linux和windows进程同步与线程同步那些事儿(三): Linux线程同步详解示例 Linux和windows进程同步与线程同步那些事儿(四):windows 下进程同步 Linux和wi

    2024年02月01日
    浏览(39)
  • 数据库定时备份linux篇

    目录 1 序言 2 crond 相关知识点 2.1 crond 是什么? 2.2 crontab 进行定时任务设置 2.2.1 crontab 指令选项说明 2.2.2 crontab 指令使用格式 2.2.3 特定时间执行任务例子 2.2.4 crontab 设置步骤 3 各个数据库备份脚本 3.1 Oracle数据库 3.2 Mysql数据库 3.3 postgresql数据库 3.4 mongoDB数据库 4 定时备份数据

    2024年02月04日
    浏览(60)
  • Linux达梦数据库安装

    说明: 达梦官方推荐是创建新的用户进行安装,但是在公司自己私创用户是违规的,也可以直接使用root用户进行安装,新用户和使用root安装不同点我会标注出来。 a、创建用户组dinstall.   groupadd dinstall  b、创建安装用户dmdba.   useradd -g dinstall -m -d /home/dmdba -s /bin/bash d

    2024年02月09日
    浏览(71)
  • Linux 使用bash创建MYSQL数据库并导入数据库文件

    主要是杠一下的数据库123-456.sql,这个神经病一样,试了很多写法

    2024年01月22日
    浏览(67)
  • Linux 线程和线程同步

     【操作系统】2.进程和线程 - imXuan - 博客园 (cnblogs.com) 线程:light weight process(LWP)轻量级的进程,在 Linux 中本质上仍然是一个进程 进程:有独立的地址空间,独立PCB,可以当作只有一个线程的进程。进程是计算机 资源分配的最小单位 线程:有独立的PCB,共享物理地址空间

    2024年02月05日
    浏览(41)
  • linux环境安装mysql数据库

    一:查看是否自带mariadb数据库 命令:rpm -qa | grep mariadb 如果自带数据库则卸载掉重新安装 命令:yum remove mariadb-connector-c-3.1.11-2.el8_3.x86_64 二:下载mysql 命令:wget -i -c http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm 注意:如果出现No such file or directory,运行命令:su root 三

    2024年02月15日
    浏览(56)
  • linux系统--------------mysql数据库管理

    目录 一、SQL语句 1.1SQL语言分类 1.2查看数据库信息    1.3登录到你想登录的库 1.4查看数据库中的表信息 1.5显示数据表的结构(字段) 1.5.1数据表的结构 1.5.2常用的数据类型: 二、关系型数据库的四种语言 2.1DDL:数据定义语言,用于创建数据库对象,如库、表、索引等 2.1.1库

    2024年03月24日
    浏览(53)
  • Linux 导入MySQL数据库(四)

    一、导出数据库用mysqldump命令(注意mysql的安装路径,即此命令的路径): 1、导出数据和表结构: 敲回车后会提示输入密码 PS: 在Linux命令中, 符号用于将命令的输出重定向到文件中。在这个例子中,mysqldump命令将数据库abc的数据和表结构导出到一个名为abc.sql的文件中。如

    2024年02月09日
    浏览(51)
  • Linux下oracle数据库启动

    1.登录到Linux服务器(ssh) 2.切换到oracle用户权限 (命令是: # su –l oracle ) 3.进入sqlplus界面(命令是:$ sqlplus /nolog 或 sqlplus / as sysdba) 原本的画面会变为 SQL 接着请输入 SQLconn / as sysdba ; 输入 SQL startup (作用:启动数据库实例) 另外停止数据库的指令如下: SQL shutdown immediate 回到

    2024年02月10日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包