目录
线程和线程锁概念
线程锁的概念
线程的特点
线程的使用
创建线程 pthread_create
回收线程pthread_join
退出线程 pthread_exit
线程锁的使用
线程同步之互斥锁(Mutex)
初始化互斥锁
获取互斥锁
释放互斥锁
销毁互斥锁
初始化条件变量
等待条件变量
发送信号
广播信号
销毁条件变量
实例:每次打印都实现翻转数组
线程和线程锁概念
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含一个或多个线程,而每个线程都有自己的指令指针和寄存器状态,它们共享进程的资源,如内存空间、文件句柄和网络连接等。
线程锁的概念
线程锁的基本思想是,只有一个线程能持有锁,其他试图获取锁的线程将被阻塞,直到锁被释放。这样,锁就确保了在任何时刻,只有一个线程能够访问临界区(即需要保护的代码段或数据),从而保证了数据的完整性和一致性。
线程的特点
-
轻量级进程:相比进程,线程的创建和切换成本更低,因为它们共享相同的地址空间和资源,不需要进行系统调用和上下文切换。
-
并发执行:线程允许在一个进程内部并发执行多个控制流,使得程序能够同时处理多个任务,提高程序的响应速度和效率。
-
资源共享:线程共享进程的资源,如内存、文件句柄和网络连接等,这减少了资源的开销,但也要求对共享资源进行同步和保护,以防止数据竞争和不一致。
-
通信便捷:由于线程共享同一进程的资源,它们之间的通信比进程间通信更为简单和快速,通常只需要使用局部变量或全局变量即可。
-
独立调度和执行:线程可以独立于其他线程进行调度和执行,操作系统可以根据需要将CPU时间分配给不同的线程,而无需切换到不同的进程。
-
线程状态:线程也有自己的生命周期,包括创建、就绪、运行、阻塞和终止等状态。线程状态的变化由操作系统调度器控制。
-
线程同步:为了保证数据的一致性和完整性,线程在访问共享资源时需要进行同步。常用的同步机制包括互斥锁(mutex)、信号量(semaphore)、条件变量(condition variable)等。
-
线程间通信:虽然线程共享资源,但在某些情况下,线程之间也需要进行通信,如通知某一线程完成特定任务或传递数据。这可以通过共享内存、信号量或条件变量等方式实现。
-
线程优先级:线程可以有不同的优先级,高优先级的线程在调度时会得到更多的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
失败:错误码
回收线程pthread_join
int pthread_join(pthread_t thread, void **value_ptr)
功能:用于等待一个指定的线程结束,阻塞函数
参数:thread:创建的线程对象
value_ptr:指针*value_ptr指向线程返回的参数
返回值:成功 : 0
失败:errno
退出线程 pthread_exit
int pthread_exit(void *value_ptr)
功能:用于退出线程的执行
参数:value_ptr:线程退出时返回的值(任意类型)
返回值:成功 : 0
失败:errno
简单用线程实现一下主线程循环从终端输入,线程函数将数据循环输出,当输入quit结束程序。
线程锁的使用
线程同步之互斥锁(Mutex)
互斥锁(Mutex)是一种用于同步线程访问共享资源的机制,确保在任何时刻只有一个线程能够访问临界区,从而避免了数据竞争和不一致性问题。以下是互斥锁相关函数的详细解析:
初始化互斥锁
C
1int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
- 功能:初始化互斥锁。
- 参数:
mutex
:指向要初始化的互斥锁的指针。attr
:指向互斥锁属性结构的指针,如果为NULL
,则使用默认属性。
- 返回值:成功返回
0
,失败返回非零值。
获取互斥锁
C
1int pthread_mutex_lock(pthread_mutex_t *mutex);
- 功能:尝试获取互斥锁,如果锁已经被另一个线程持有,当前线程将被阻塞,直到锁可用。
- 参数:
mutex
:指向要获取的互斥锁的指针。
- 返回值:成功返回
0
,失败返回非零值。
注:pthread_mutex_lock
与pthread_mutex_trylock
的区别在于,pthread_mutex_lock
是阻塞的,即如果锁被占用,调用线程会等待直至获取到锁;而pthread_mutex_trylock
是非阻塞的,如果锁被占用,它会立即返回,不等待锁释放。
释放互斥锁
C
1int pthread_mutex_unlock(pthread_mutex_t *mutex);
- 功能:释放由当前线程持有的互斥锁。
- 参数:
mutex
:指向要释放的互斥锁的指针。
- 返回值:成功返回
0
,失败返回非零值。
销毁互斥锁
C
1int pthread_mutex_destroy(pthread_mutex_t *mutex);
- 功能:销毁互斥锁,通常在不再需要互斥锁时调用。
- 参数:
mutex
:指向要销毁的互斥锁的指针。
- 返回值:成功返回
0
,失败返回非零值。
初始化条件变量
C
1int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
- 功能:初始化条件变量。
- 参数:
cond
:指向要初始化的条件变量的指针。attr
:指向条件变量属性的指针,通常设为NULL
以使用默认属性。
- 返回值:成功返回
0
,失败返回非零值。
等待条件变量
C
1int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
- 功能:线程挂起等待,直到条件变量被信号唤醒。
- 参数:
cond
:指向要等待的条件变量的指针。mutex
:与条件变量关联的互斥锁,必须在调用前锁定并在返回后再次锁定。
- 返回值:成功返回
0
,失败返回非零值。 - 注释:当没有条件产生时函数会阻塞,同时会自动解锁互斥锁;一旦条件产生或接收到信号,函数结束阻塞并重新锁定互斥锁。
发送信号
C
1int pthread_cond_signal(pthread_cond_t *cond);
- 功能:向条件变量发送信号,唤醒一个等待该条件变量的线程。
- 参数:
cond
:指向条件变量的指针。
- 返回值:成功返回
0
,失败返回非零值。 - 注释:通常在条件满足后调用,以通知等待线程继续执行。
广播信号
C
1int pthread_cond_broadcast(pthread_cond_t *cond);
- 功能:向条件变量广播信号,唤醒所有等待该条件变量的线程。
- 参数:
cond
:指向条件变量的指针。
- 返回值:成功返回
0
,失败返回非零值。 - 注释:与
pthread_cond_signal
类似,但唤醒所有等待线程,而非仅唤醒一个。
销毁条件变量
C
1int pthread_cond_destroy(pthread_cond_t *cond);
- 功能:销毁条件变量。
- 参数:
cond
:指向要销毁的条件变量的指针。
- 返回值:成功返回
0
,失败返回非零值。
实例:每次打印都实现翻转数组
.
注:由于线程是随机执行的,所以此时我们不得不用上互斥锁,否则就会出现一些意外情况,这与我们使用标志位是一个道理,例如flag为true的时候p1执行,为flase的p2执行,但是线程锁的逻辑更加严谨和细致一些,功能也更多一些。