跳转到内容

多线程编程

更新: 3/3/2025 字数: 0 字 时长: 0 分钟

线程使用

获取线程号

c
//获取线程号
#include <pthread.h>
pthread_t pthread_self(void);

线程创建

c
//创建线程
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
  • 该函数第一个参数为 pthread_t 指针,用来保存新建线程的线程号;

  • 第二个参数表示了线程的属性,一般传入 NULL 表示默认属性;

  • 第三个参数是一个函数指针,就是线程执行的函数。这个函数返回值为 void*,形参为void*;

  • 第四个参数则表示为向线程处理函数传入的参数,若不传入,可用 NULL 填充,有关线程传参后续小节会有详细的说明,接下来通过一个简单例程来使用该函数创建出一个线程。

例程

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

void *fun1(void *arg)
{
	printf("%s:arg = %d Addr = %p\n",__FUNCTION__,*(int *)arg,arg);
}

void *fun2(void *arg)
{
	printf("%s:arg = %d Addr = %p\n",__FUNCTION__,(int)(long)arg,arg);
}

int main()
{

	pthread_t tid1,tid2;
	int a = 50;
	int ret = pthread_create(&tid1,NULL,fun1,(void *)&a);
	if(ret != 0){
		perror("pthread_create");
		return -1;
	}
	ret = pthread_create(&tid2,NULL,fun2,(void *)(long)a);
	if(ret != 0){
		perror("pthread_create");
		return -1;
	}
	sleep(1);
	printf("%s:a = %d Add = %p \n",__FUNCTION__,a,&a);
	return 0;
}

线程的退出与回收

1. 线程主动退出

c
//线程主动退出
#include <pthread.h>
void pthread_exit(void *retval);

​ pthread_exit 函数为线程退出函数,在退出时候可以传递一个 void*类型的数据带给主线程,若选择不传出数据,可将参数填充为 NULL。

2. 线程被动退出

c
//线程被动退出,其他线程使用该函数让另一个线程退出
#include <pthread.h>
int pthread_cancel(pthread_t thread);
//成功:返回 0

​ 该函数传入一个 tid 号,会强制退出该 tid 所指向的线程,若成功执行会返回 0。

3. 线程资源回收(阻塞方式)

c
//线程资源回收(阻塞)
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

​ 该函数为线程回收函数,默认状态为阻塞状态,直到成功回收线程后才返回。第一个参数为要回收线程的 tid 号,第二个参数为线程回收后接受线程传出的数据。

4. 线程资源回收(非阻塞方式)

c
线程资源回收(非阻塞)
#define _GNU_SOURCE
#include <pthread.h>
int pthread_tryjoin_np(pthread_t thread, void **retval);

该函数为非阻塞模式回收函数,通过返回值判断是否回收掉线程,成功回收则返回 0,其余参数与 pthread_join 一致。

线程控制

互斥锁 API

1. 初始化互斥量

c
int pthread_mutex_init(phtread_mutex_t *mutex,const pthread_mutexattr_t *restrict attr);

该函数初始化一个互斥量,第一个参数是改互斥量指针,第二个参数为控制 互斥量的属性,一般为 NULL。当函数成功后会返回 0,代表初始化互斥量成功。

当然初始化互斥量也可以调用宏来快速初始化,代码如下:

c
pthread_mutex_t mutex = PTHREAD_MUTEX_INITALIZER;

2. 互斥量加锁/解锁

c
//互斥量加锁(阻塞) /解锁
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
//成功:返回 0

lock函数与unlock函数分别为加锁解锁函数,只需要传入已经初始化好的pthread_mutex_t 互斥量指针。 成功后会返回 0。

当某一个线程获得了执行权后,执行lock函数,一旦加锁成功后,其余线程遇到lock函数时候会发生阻塞,直至获取资源的线程执行unlock函数后。unlock 函数会唤醒其他正在等待互斥量的线程。

特别注意的是,当获取lock之后,必须在逻辑处理结束后执行unlock,否则会发生死锁现象!导致其余线程一 直处于阻塞状态,无法执行下去。在使用互斥量的时候,尤其要注意使用pthread_cancel函数,防止发生死锁现象!

3. 互斥量加锁(非阻塞方式)

c
//互斥量加锁(非阻塞)
#include <pthread.h>
int pthread_mutex_trylock(pthread_mutex_t *mutex);
c
//互斥量销毁
#include <pthread.h>
int pthread_mutex_destory(pthread_mutex_t *mutex);
//成功:返回 0

例程

c
#define _GNU_SOURCE 
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

pthread_mutex_t mutex;

int Num = 0;

void *fun1(void *arg)
{
	pthread_mutex_lock(&mutex);
	while(Num < 3){
		Num++;
		printf("%s:Num = %d\n",__FUNCTION__,Num);
		sleep(1);
	}
	pthread_mutex_unlock(&mutex);
	pthread_exit(NULL);
}

void *fun2(void *arg)
{
	pthread_mutex_lock(&mutex);
	while(Num > -3){
		Num--;
		printf("%s:Num = %d\n",__FUNCTION__,Num);
		sleep(1);
	}
	pthread_mutex_unlock(&mutex);
	pthread_exit(NULL);
}

int main()
{
	int ret;
	pthread_t tid1,tid2;
	ret = pthread_mutex_init(&mutex,NULL);
	if(ret != 0){
		perror("pthread_mutex_init");
		return -1;
	}
	ret = pthread_create(&tid1,NULL,fun1,NULL);
	if(ret != 0){
		perror("pthread_create");
		return -1;
	}
	ret = pthread_create(&tid2,NULL,fun2,NULL);
	if(ret != 0){
		perror("pthread_create");
		return -1;
	}
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	pthread_mutex_destroy(&mutex);
	return 0;
}

信号量API

TODO