linux网络编程----->线程死锁

简介:

   开发使用多线程过程中, 不可避免的会出现多个线程同时操作同一块共享资源, 当操作全部为读时, 不会出现未知结果, 一旦当某个线程操作中有写操作时, 就会出现数据不同步的事件. 

    而出现数据混乱的原因:

    • 资源共享(独享资源则不会)

    • 调试随机(对数据的访问会出现竞争)

    • 线程间缺少必要的同步机制   

    以上三点, 前两点不能被改变. 欲提高效率, 传递数据, 资源必须共享. 只要资源共享, 就一定会出现线程间资源竞争, 只要存在竞争关系, 数据就会出现混乱.

    所以只能从第三点着手, 使多个线程在访问共享资源的时候, 出现互斥.


线程同步:

    指在一定的时间里只允许某一个进程访问某个资源,而在此时间内,不允许其它线程对该资源进行操作.

    

    在使用锁的时候, 以下会出现死锁状态.

    • 线程试图对一把锁进行加锁两次

    • 哲学家就餐[N个哲学家, N支筷子, 哲学家同时对一个方向取筷子, 取到后需要拿另一方面的场子才可以就餐]  


    线程试图对一把锁进行加锁两次:

    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
/*
  *   模拟一个线程对一把锁进行加锁两次
  *   author sea time 2016/06/15
  */
 
//创建一把互斥锁, 并进行静态初始化
pthread_mutex_t mutex =  PTHREAD_MUTEX_INITIALIZER;
 
//线程函数
void * thread_handler( void * args){
     //第一次获取锁成功
     pthread_mutex_lock(&mutex);
     //成功获取打印
     printf ( "get mutex 1 successfully!\n" );
     //第二次获取同一把锁
     pthread_mutex_lock(&mutex);
     printf ( "get mutex 2 successfully!\n" );
     pthread_mutex_unlock(&mutex);
     pthread_mutex_unlock(&mutex);
     
     pthread_exit(NULL);
}
 
int  main( int  argc,  char * argv[]){
     pthread_t tid;
     pthread_create(&tid, NULL, thread_handler, NULL);
 
     //等待线程结束
     pthread_join(tid, NULL);
 
     //释放互斥锁
     pthread_mutex_destroy(&mutex);
     return  0;
}

    运行结果:

    wKioL1dhcbXCI0_0AAAt9kDZn90862.png-wh_50

    结果如预期所至, 一直阻塞在那获取锁.


    哲学家就餐[N个哲学家, N支筷子, 哲学家同时对一个方向取筷子, 取到后需要拿另一方面的场子才可以就餐]:


    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
/*
  * 模拟哲学家用餐模型
  *  author sea time 2016/0615
  */
  //用五把锁模拟五支筷子
pthread_mutex_t mutex[5];
 
void * thread_handler( void * args){
     //获取当前位数
     long  i = ( long )args;
     int  left, right;
     //当是最后一个哲学家
     if ( sizeof (mutex)/ sizeof (*mutex) == i + 1){
         left = i;
         right = 0;
     }
     else {
         left = i;
         right = i + 1;
     }
     //获取左边的筷子
     pthread_mutex_lock(&mutex[left]);
     //等待100毫秒, 让其它线程都拿到自己右边的筷子
     usleep(100);
     //获取右边的筷子
     pthread_mutex_lock(&mutex[right]);
     sleep(2);
     printf ( "%ld 吃完了....!\n" , i);
     //解锁
     pthread_mutex_unlock(&mutex[right]);
     //解锁
     pthread_mutex_unlock(&mutex[left]);
 
     pthread_exit(NULL);
}
int  main( int  argc,  char * argv[]){
     long  i = 0;
     int  ret = 0;
     pthread_t tid[5];
     
 
     //初始化五把锁
     for (i = 0; i <  sizeof (mutex)/ sizeof (*mutex); i++){
         pthread_mutex_init(mutex+i, NULL);
     }
 
     //创建五个线程
     for (i = 0; i <  sizeof (tid)/ sizeof (*tid); i++){
         pthread_create(tid+i, NULL, thread_handler, ( void *)i);
     }
 
     //等待线程
     for (i = 0; i <  sizeof (tid) /  sizeof (*tid); i++){
         pthread_join(tid[i], NULL);
     }
     
     //释放五把锁
     for (i = 0; i <  sizeof (mutex)/ sizeof (*mutex); i++){
         pthread_mutex_destroy(mutex+i);
     }
     return  ret;
}

    运行结果: 会一直阻塞


结论: 在访问共享资源前加锁,访问结束后立即解锁。锁的“粒度”应越小越好。








      本文转自asd1123509133 51CTO博客,原文链接:http://blog.51cto.com/lisea/1789733,如需转载请自行联系原作者


相关文章
|
6月前
|
负载均衡 算法 安全
基于Reactor模式的高性能网络库之线程池组件设计篇
EventLoopThreadPool 是 Reactor 模式中实现“一个主线程 + 多个工作线程”的关键组件,用于高效管理多个 EventLoop 并在多核 CPU 上分担高并发 I/O 压力。通过封装 Thread 类和 EventLoopThread,实现线程创建、管理和事件循环的调度,形成线程池结构。每个 EventLoopThread 管理一个子线程与对应的 EventLoop(subloop),主线程(base loop)通过负载均衡算法将任务派发至各 subloop,从而提升系统性能与并发处理能力。
365 3
|
3月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
236 1
|
3月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
248 2
|
11月前
|
存储 Linux API
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
在计算机系统的底层架构中,操作系统肩负着资源管理与任务调度的重任。当我们启动各类应用程序时,其背后复杂的运作机制便悄然展开。程序,作为静态的指令集合,如何在系统中实现动态执行?本文带你一探究竟!
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
|
9月前
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
333 67
|
10月前
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
471 23
|
11月前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
224 26
|
11月前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
227 17
|
Java 应用服务中间件
面对海量网络请求,Tomcat线程池如何进行扩展?
【10月更文挑战第4天】本文详细探讨了Tomcat线程池相较于标准Java实用工具包(JUC)线程池的关键改进。首先,Tomcat线程池在启动时即预先创建全部核心线程,以应对启动初期的高并发请求。其次,通过重写阻塞队列的入队逻辑,Tomcat能够在任务数超过当前线程数但未达最大线程数时,及时创建非核心线程,而非等到队列满才行动。此外,Tomcat还引入了在拒绝策略触发后重新尝试入队的机制,以提高吞吐量。这些优化使得Tomcat线程池更适应IO密集型任务,有效提升了性能。
面对海量网络请求,Tomcat线程池如何进行扩展?
|
Java Linux
【网络】高并发场景处理:线程池和IO多路复用
【网络】高并发场景处理:线程池和IO多路复用
397 2