C语言多线程基础(pthread)

时间:2024-01-23 08:15:23


1.线程和进程的概念

  • 线程:进程中的一个实体,是CPU调度和分派的基本单位。可以与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一进程中的多个线程之间可以并发执行,线程在运行中呈现间断性。
  • 进程:具有一定独立功能的程序关于数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。进程是一个可拥有资源的独立单位,可以独立调度和分派的基本单位。

 

 2. 线程的创建pthread_create()

#include <pthread.h>//需要添加pthread.h头文件
int pthread_create(
                 pthread_t *thread,   //指向线程标识符的指针,用pthread_t创建
                 const pthread_attr_t *attr,  //设置线程属性,默认为NULL
                 void *(*start_rtn)(void *), //线程运行函数的起始地址
                 void *arg //传递给线程函数的参数
                  );

创建一个基本的线程程序如下main.cpp:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
 
void* ptintf_hello_world(void* tid);
 
int main(void){
    pthread_t thread;
    int status;
	int i = 10;
    printf("Main here. Creating thread %d\n",i);
    status=pthread_create(&thread, NULL, ptintf_hello_world, &i); 
    pthread_join(thread,NULL);  //pthread_join函数以阻塞的方式等待指定的线程结束,如果线程已经结束,函数会立即返回	
    if(status!=0){
        printf("pthread_create returned error code %d\n", status);
    	exit(-1);
	}
	exit(0);
}
void* ptintf_hello_world(void* tid){
	printf("Hello world %d.\n", *(int*)tid);
	exit(0);
}

Android.mk :

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
 
LOCAL_CFLAGS += -DAWINIC_DEBUG
LOCAL_VENDOR_MODULE := true
LOCAL_LDLIBS    := -llog
 
LOCAL_SRC_FILES := main.cpp
LOCAL_MODULE := addValTest
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
 
include $(BUILD_EXECUTABLE)

 Application.mk:

APP_PLATFORM := android-26
APP_ABI := arm64-v8a, armeabi-v7a
APP_STL := c++_static

创建jni文件夹,然后将main.cpp、Android.mk 、Application.mk三个文件放入jni文件夹下,然后再jni同级目录打开cmd窗口,执行ndk-build,即可生成可执行文件addValTest,然后push到手机system/bin目录下执行:

C语言多线程基础(pthread)_子线程

3. 等待线程结束pthread_join()

先看下面程序:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUMBER_OF_THREADS 10
 
void* ptintf_hello_world(void* tid);
int main(void){
    pthread_t threads[NUMBER_OF_THREADS];
    int status = 0;
	int i = 0;
    for(i=0; i < NUMBER_OF_THREADS; i++){//循环创建10个线程
    	printf("Main here. Creating thread %d\n",i);
        //创建线程,线程函数传入参数为i
    	status = pthread_create(&threads[i], NULL,ptintf_hello_world, &i);
		if(status != 0){//线程创建不成功,打印错误信息
    		printf("pthread_create returned error code %d\n", status);
    		exit(-1);
		}
	}
	exit(0);
}
void* ptintf_hello_world(void* tid){
	printf("Hello world %d.\n", *(int*)tid);//在线程函数中打印函数的参数
	pthread_exit(0);
}

运行结果:

C语言多线程基础(pthread)_pthread_02

由于我们没有在主线程中等待我们创建出来的10个线程执行完毕,所以创建出来的子线程可能还没来得及执行,就因为主线程(main函数)执行完毕而终止整个进程,导致子线程没法运行。因此printf得到的“Hello world”不是10个,其数量是无法预知的,其顺序也是无法预知的。而且传的是地址,子线程在执行时,i值可能还没更新,所以可能会打印重复的值。

此时我们就需要pthread_join()函数来等待线程执行完成。

pthread_join()函数的原型如下:

int pthread_join(pthread_t thread,    //线程标识符,即线程ID,标识唯一线程
                 void **retval);    //用户定义的指针,用来存储被等待线程的返回值。
//返回值:0:成功;其他:失败的错误号

使用pthread_join()函数之后的代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUMBER_OF_THREADS 10
 
void* ptintf_hello_world(void* tid);
int main(void){
    pthread_t threads[NUMBER_OF_THREADS];
    int status = 0;
	int i = 0;
    for(i=0; i < NUMBER_OF_THREADS; i++){//循环创建10个现场
    	printf("Main here. Creating thread %d\n",i);
        //创建线程,线程函数传入参数为i
    	status=pthread_create(&threads[i], NULL, ptintf_hello_world, &i);
		if(status != 0){//线程创建不成功,打印错误信息
    		printf("pthread_create returned error code %d\n", status);
    		exit(-1);
		}
	}
	for(i=0; i < NUMBER_OF_THREADS; i++){
		pthread_join(threads[i], NULL);
	}
	exit(0);
}
void* ptintf_hello_world(void* tid){
	printf("Hello world %d.\n", *(int*)tid);//在线程函数中打印函数的参数
	pthread_exit(0);
}

C语言多线程基础(pthread)_子线程_03

可以看出,此时所有子线程都执行完毕,打印了10个。但是线程执行的顺序是不固定的,也就是说我们无法预知打印的顺序。根据代码判断程序的输出是不可行的,我们只知道输出的内容,但不知道输出的顺序。

除非我们在每个子线程创建之后,一直等其运行结束,然后才开始创建下一个子线程。即将pthread_join()函数放到紧挨着pthread_create()函数的后面,代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUMBER_OF_THREADS 10
 
void* ptintf_hello_world(void* tid);
int main(void){
    pthread_t threads[NUMBER_OF_THREADS];
    int status = 0;
	int i = 0;
    for(i=0; i < NUMBER_OF_THREADS; i++){//循环创建10个现场
    	printf("Main here. Creating thread %d\n",i);
        //创建线程,线程函数传入参数为i
    	status=pthread_create(&threads[i], NULL, ptintf_hello_world, &i);
        pthread_join(threads[i], NULL);
		if(status!=0){//线程创建不成功,打印错误信息
    		printf("pthread_create returned error code %d\n",status);
    		exit(-1);
		}
	}
	exit(0);
}
void* ptintf_hello_world(void* tid){
	printf("Hello world %d.\n", *(int*)tid);//在线程函数中打印函数的参数
	pthread_exit(0);
}

运行结果如下: 

C语言多线程基础(pthread)_i++_04

4. 使用pthread_join()得到线程函数的返回值

使用pthread_join()除了有阻塞线程功能之外,还可以利用其第二个参数,得到线程函数的返回值。代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUMBER_OF_THREADS 10
 
void* ptintf_hello_world(void* tid);
int main(void){
    pthread_t threads[NUMBER_OF_THREADS];
    int status = 0;
	int i = 0;
    for(i=0; i<NUMBER_OF_THREADS; i++){
    	printf("Main here. Creating thread %d\n",i);
    	status = pthread_create(&threads[i], NULL, ptintf_hello_world, &i);
		//使用res得到线程函数的返回值 
        int** res=(int**)malloc(sizeof(int*));
		pthread_join(threads[i],(void**)res);  //pthread_join函数以阻塞的方式等待指定的线程结束
    	printf("res[%d]:%d\n",i,**res);//打印线程函数的返回值 
		free(*res); //释放线程处理函数中使用malloc分配的内存空间 
		if(status!=0){
    		printf("pthread_create returned error code %d\n",status);
    		exit(-1);
		}
	}
 
	exit(0);
}
void* ptintf_hello_world(void* tid){
	int val = *(int*)tid;
	printf("Hello world %d.\n", val);
	int* a=(int*)malloc(sizeof(int));
	*a= val * val;
	return a;	//线程函数的返回值 
}

运行结果如下:

C语言多线程基础(pthread)_i++_05

参考链接: C语言——多线程基础(pthread)