深入浅出:C语言线程以及线程锁

简介: 线程锁的基本思想是,只有一个线程能持有锁,其他试图获取锁的线程将被阻塞,直到锁被释放。这样,锁就确保了在任何时刻,只有一个线程能够访问临界区(即需要保护的代码段或数据),从而保证了数据的完整性和一致性。线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含一个或多个线程,而每个线程都有自己的指令指针和寄存器状态,它们共享进程的资源,如内存空间、文件句柄和网络连接等。线程锁的概念

目录

线程和线程锁概念

线程锁的概念

线程的特点

线程的使用

创建线程 pthread_create

回收线程pthread_join

退出线程 pthread_exit

线程锁的使用

线程同步之互斥锁(Mutex)

初始化互斥锁

获取互斥锁

释放互斥锁

销毁互斥锁

初始化条件变量

等待条件变量

发送信号

广播信号

销毁条件变量

实例:每次打印都实现翻转数组


线程和线程锁概念

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含一个或多个线程,而每个线程都有自己的指令指针和寄存器状态,它们共享进程的资源,如内存空间、文件句柄和网络连接等。

线程锁的概念

线程锁的基本思想是,只有一个线程能持有锁,其他试图获取锁的线程将被阻塞,直到锁被释放。这样,锁就确保了在任何时刻,只有一个线程能够访问临界区(即需要保护的代码段或数据),从而保证了数据的完整性和一致性。

线程的特点

  1. 轻量级进程:相比进程,线程的创建和切换成本更低,因为它们共享相同的地址空间和资源,不需要进行系统调用和上下文切换。
  2. 并发执行:线程允许在一个进程内部并发执行多个控制流,使得程序能够同时处理多个任务,提高程序的响应速度和效率。
  3. 资源共享:线程共享进程的资源,如内存、文件句柄和网络连接等,这减少了资源的开销,但也要求对共享资源进行同步和保护,以防止数据竞争和不一致。
  4. 通信便捷:由于线程共享同一进程的资源,它们之间的通信比进程间通信更为简单和快速,通常只需要使用局部变量或全局变量即可。
  5. 独立调度和执行:线程可以独立于其他线程进行调度和执行,操作系统可以根据需要将CPU时间分配给不同的线程,而无需切换到不同的进程。
  6. 线程状态:线程也有自己的生命周期,包括创建、就绪、运行、阻塞和终止等状态。线程状态的变化由操作系统调度器控制。
  7. 线程同步:为了保证数据的一致性和完整性,线程在访问共享资源时需要进行同步。常用的同步机制包括互斥锁(mutex)、信号量(semaphore)、条件变量(condition variable)等。
  8. 线程间通信:虽然线程共享资源,但在某些情况下,线程之间也需要进行通信,如通知某一线程完成特定任务或传递数据。这可以通过共享内存、信号量或条件变量等方式实现。
  9. 线程优先级:线程可以有不同的优先级,高优先级的线程在调度时会得到更多的CPU时间,从而影响线程的执行顺序和进程的整体性能。

线程的使用

创建线程 pthread_create

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, 
                    void *(*start_routine) (void *), void *arg);
功能:创建线程
参数:thread:线程标识
            attr:线程属性, NULL:代表设置默认属性
            start_routine:函数名:代表线程函数
            arg:用来给前面函数传参
返回值:成功:0
              失败:错误码

image.gif

回收线程pthread_join

int  pthread_join(pthread_t thread,  void **value_ptr) 
功能:用于等待一个指定的线程结束,阻塞函数
参数:thread:创建的线程对象
        value_ptr:指针*value_ptr指向线程返回的参数
返回值:成功 : 0
       失败:errno

image.gif

退出线程 pthread_exit

int  pthread_exit(void *value_ptr) 
功能:用于退出线程的执行
参数:value_ptr:线程退出时返回的值(任意类型)
返回值:成功 : 0
        失败:errno

image.gif

简单用线程实现一下主线程循环从终端输入,线程函数将数据循环输出,当输入quit结束程序。

image.gif 编辑

线程锁的使用

线程同步之互斥锁(Mutex)

互斥锁(Mutex)是一种用于同步线程访问共享资源的机制,确保在任何时刻只有一个线程能够访问临界区,从而避免了数据竞争和不一致性问题。以下是互斥锁相关函数的详细解析:

初始化互斥锁

C

1int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);

image.gif

  • 功能:初始化互斥锁。
  • 参数
  • mutex:指向要初始化的互斥锁的指针。
  • attr:指向互斥锁属性结构的指针,如果为NULL,则使用默认属性。
  • 返回值:成功返回0,失败返回非零值。

获取互斥锁

C

1int pthread_mutex_lock(pthread_mutex_t *mutex);

image.gif

  • 功能:尝试获取互斥锁,如果锁已经被另一个线程持有,当前线程将被阻塞,直到锁可用。
  • 参数
  • mutex:指向要获取的互斥锁的指针。
  • 返回值:成功返回0,失败返回非零值。

pthread_mutex_lockpthread_mutex_trylock的区别在于,pthread_mutex_lock是阻塞的,即如果锁被占用,调用线程会等待直至获取到锁;而pthread_mutex_trylock是非阻塞的,如果锁被占用,它会立即返回,不等待锁释放。

释放互斥锁

C

1int pthread_mutex_unlock(pthread_mutex_t *mutex);

image.gif

  • 功能:释放由当前线程持有的互斥锁。
  • 参数
  • mutex:指向要释放的互斥锁的指针。
  • 返回值:成功返回0,失败返回非零值。

销毁互斥锁

C

1int pthread_mutex_destroy(pthread_mutex_t *mutex);

image.gif

  • 功能:销毁互斥锁,通常在不再需要互斥锁时调用。
  • 参数
  • mutex:指向要销毁的互斥锁的指针。
  • 返回值:成功返回0,失败返回非零值。

初始化条件变量

C

1int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

image.gif

  • 功能:初始化条件变量。
  • 参数
  • cond:指向要初始化的条件变量的指针。
  • attr:指向条件变量属性的指针,通常设为NULL以使用默认属性。
  • 返回值:成功返回0,失败返回非零值。

等待条件变量

C

1int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

image.gif

  • 功能:线程挂起等待,直到条件变量被信号唤醒。
  • 参数
  • cond:指向要等待的条件变量的指针。
  • mutex:与条件变量关联的互斥锁,必须在调用前锁定并在返回后再次锁定。
  • 返回值:成功返回0,失败返回非零值。
  • 注释:当没有条件产生时函数会阻塞,同时会自动解锁互斥锁;一旦条件产生或接收到信号,函数结束阻塞并重新锁定互斥锁。

发送信号

C

1int pthread_cond_signal(pthread_cond_t *cond);

image.gif

  • 功能:向条件变量发送信号,唤醒一个等待该条件变量的线程。
  • 参数
  • cond:指向条件变量的指针。
  • 返回值:成功返回0,失败返回非零值。
  • 注释:通常在条件满足后调用,以通知等待线程继续执行。

广播信号

C

1int pthread_cond_broadcast(pthread_cond_t *cond);

image.gif

  • 功能:向条件变量广播信号,唤醒所有等待该条件变量的线程。
  • 参数
  • cond:指向条件变量的指针。
  • 返回值:成功返回0,失败返回非零值。
  • 注释:与pthread_cond_signal类似,但唤醒所有等待线程,而非仅唤醒一个。

销毁条件变量

C

1int pthread_cond_destroy(pthread_cond_t *cond);

image.gif

  • 功能:销毁条件变量。
  • 参数
  • cond:指向要销毁的条件变量的指针。
  • 返回值:成功返回0,失败返回非零值。

实例:每次打印都实现翻转数组

. image.gif 编辑

image.gif 编辑

注:由于线程是随机执行的,所以此时我们不得不用上互斥锁,否则就会出现一些意外情况,这与我们使用标志位是一个道理,例如flag为true的时候p1执行,为flase的p2执行,但是线程锁的逻辑更加严谨和细致一些,功能也更多一些。

相关文章
|
14天前
|
Java
并发编程的艺术:Java线程与锁机制探索
【6月更文挑战第21天】**并发编程的艺术:Java线程与锁机制探索** 在多核时代,掌握并发编程至关重要。本文探讨Java中线程创建(`Thread`或`Runnable`)、线程同步(`synchronized`关键字与`Lock`接口)及线程池(`ExecutorService`)的使用。同时,警惕并发问题,如死锁和饥饿,遵循最佳实践以确保应用的高效和健壮。
25 2
|
5天前
|
分布式计算 并行计算 安全
在Python Web开发中,Python的全局解释器锁(Global Interpreter Lock,简称GIL)是一个核心概念,它直接影响了Python程序在多线程环境下的执行效率和性能表现
【6月更文挑战第30天】Python的GIL是CPython中的全局锁,限制了多线程并行执行,尤其是在多核CPU上。GIL确保同一时间仅有一个线程执行Python字节码,导致CPU密集型任务时多线程无法充分利用多核,反而可能因上下文切换降低性能。然而,I/O密集型任务仍能受益于线程交替执行。为利用多核,开发者常选择多进程、异步IO或使用不受GIL限制的Python实现。在Web开发中,理解GIL对于优化并发性能至关重要。
23 0
|
2月前
|
存储 安全 Java
深入理解Java并发编程:线程安全与锁机制
【5月更文挑战第31天】在Java并发编程中,线程安全和锁机制是两个核心概念。本文将深入探讨这两个概念,包括它们的定义、实现方式以及在实际开发中的应用。通过对线程安全和锁机制的深入理解,可以帮助我们更好地解决并发编程中的问题,提高程序的性能和稳定性。
|
11天前
|
Java
Java中的`synchronized`关键字是一个用于并发控制的关键字,它提供了一种简单的加锁机制来确保多线程环境下的数据一致性。
【6月更文挑战第24天】Java的`synchronized`关键字确保多线程数据一致性,通过锁定代码块或方法防止并发冲突。同步方法整个方法体为临界区,同步代码块则锁定特定对象。示例展示了如何在`Counter`类中使用`synchronized`保证原子操作和可见性,同时指出过度使用可能影响性能。
23 4
|
14天前
|
存储 Linux C语言
c++进阶篇——初窥多线程(二) 基于C语言实现的多线程编写
本文介绍了C++中使用C语言的pthread库实现多线程编程。`pthread_create`用于创建新线程,`pthread_self`返回当前线程ID。示例展示了如何创建线程并打印线程ID,强调了线程同步的重要性,如使用`sleep`防止主线程提前结束导致子线程未执行完。`pthread_exit`用于线程退出,`pthread_join`用来等待并回收子线程,`pthread_detach`则分离线程。文中还提到了线程取消功能,通过`pthread_cancel`实现。这些基本操作是理解和使用C/C++多线程的关键。
|
15天前
|
安全 Java Python
GIL是Python解释器的锁,确保单个进程中字节码执行的串行化,以保护内存管理,但限制了多线程并行性。
【6月更文挑战第20天】GIL是Python解释器的锁,确保单个进程中字节码执行的串行化,以保护内存管理,但限制了多线程并行性。线程池通过预创建线程池来管理资源,减少线程创建销毁开销,提高效率。示例展示了如何使用Python实现一个简单的线程池,用于执行多个耗时任务。
21 6
|
18天前
|
API
linux---线程互斥锁总结及代码实现
linux---线程互斥锁总结及代码实现
|
16天前
|
调度
线程操作:锁、条件变量的使用
线程操作:锁、条件变量的使用
14 1
|
18天前
|
API
Linux---线程读写锁详解及代码实现
Linux---线程读写锁详解及代码实现
|
21天前
|
Java Python
Python中的并发编程(3)线程池、锁
Python中的并发编程(3)线程池、锁

热门文章

最新文章