简单介绍下文章结构:
1.前言
2.实验代码
3.实验结果
4.根据实验结果对代码的分析
1.前言
实验目的:理解、掌握什么是线程
实验原理:main主线程创建两个子线程,三个线程共享一块内存(指的是变量i),同时两个子线程拥有独立的上下文,不断打印共享内存的值和两个子线程各自拥有的变量(self value),通过观察打印出的值去理解什么是线程,线程的特点、内存使用、共享代码段等等一堆令我初学时懵b的东西。
2.实验代码
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
typedef struct pthread_data_s
{
int test_pthread_id;
pthread_t test_pthread;
int *in_value;
int self_value;
}pthread_data_t;
void* printf_hello_world(void* tid);
int main(void)
{
pthread_data_t test_pthread_1;
pthread_data_t test_pthread_2;
int test_pthread_ret = 0;
int test_pthread1_ret = 0;
int status, i = 10;
memset(&test_pthread_1, 0, sizeof(pthread_data_t));
memset(&test_pthread_2, 0, sizeof(pthread_data_t));
test_pthread_1.in_value = &i;
test_pthread_2.in_value = &i;
test_pthread_1.self_value = 15;
test_pthread_2.self_value = 5;
printf("Main here. Creating thread %d\n", i);
status = pthread_create(&(test_pthread_1.test_pthread), NULL, printf_hello_world, &test_pthread_1);
if (status == 0)
printf("thread created success, tp1:test_pthread_id:%d\n",test_pthread_1.test_pthread_id);
status = pthread_create(&(test_pthread_2.test_pthread), NULL, printf_hello_world, &test_pthread_2);
if (status == 0)
printf("thread created success, tp2:test_pthread_id:%d\n",test_pthread_2.test_pthread_id);
int pthread_main_self_id = 0;
sleep(2);
printf("thread1: handle_id:%d, id:%d, self_value:%d.\n",(int)test_pthread_1.test_pthread, test_pthread_1.test_pthread_id, test_pthread_1.self_value);
printf("thread2: handle_id:%d, id:%d, self_value:%d.\n",(int)test_pthread_2.test_pthread, test_pthread_2.test_pthread_id, test_pthread_2.self_value);
//pthread_join(test_pthread, NULL);
//pthread_main_self_id = pthread_self();
while (1)
{
sleep(1);
if( i >= 0)
printf("global share value:%d.\n",i);
else
break;
}
status = pthread_join(test_pthread_1.test_pthread,NULL);
if(status == 0)
printf("pthread1 exit success.\n");
else
printf("pthread1 exit error.\n");
status = pthread_join(test_pthread_2.test_pthread,NULL);
if(status == 0)
printf("pthread2 exit success.\n");
else
printf("pthread2 exit error.\n");
exit(0);
}
void* printf_hello_world(void* tid)
{
pthread_data_t *pthread_data_tmp = NULL;
pthread_data_tmp = (pthread_data_t *)tid;
pthread_data_tmp->test_pthread_id = pthread_self();
printf("Son %d thread here Hello world %d. \n", pthread_data_tmp->test_pthread_id, *(pthread_data_tmp->in_value));
while(1)
{
sleep(1);
if (*(pthread_data_tmp->in_value) <= 0 && pthread_data_tmp->self_value <=0)
break;
printf("Son:%d:\n",pthread_data_tmp->test_pthread_id);
if (*(pthread_data_tmp->in_value) >= 0)
printf(" global share value:%d.\n",(*(pthread_data_tmp->in_value))--);
if (pthread_data_tmp->self_value >= 0)
printf(" self value:%d.\n",pthread_data_tmp->self_value--);
}
pthread_exit(NULL);
}
3.实验结果
这里直接贴linux打印截图
简单说一下整个流程,
(1)主函数创建两个子线程,并且为两个子线程传递了参数,主要关注的参数为i:主线程创建的共享内存;self_value两个子线程各自拥有的变量,该变量已经初始化。
(2)主线程轮询打印全局共享内存i
与此同时
两个子线程同时对共享变量i进行-1操作,对自己拥有的变量self_value同样进行-1操作,
(3)当两个子线程将共享内存的值减到0并且将他们各自变量self_value减到0时,结束自己的线程,如果没有减到0,则继续执行。
(4)观察打印结果,可以发现,子线程1和子线程2可以一起修改共享内存i,同时各自会修改各自的值。主线程也可以访问共享内存。
(5)直到最后两个子线程完成自己任务,线程结束,主线程也结束了。
4.根据实验结果对代码的分析
(1)主线程中,我使用了pthread_exit(0)进行结束(代码中应该是pthread_exit(),忘记改了),并没有使用return。原因是:如果不使用pthread_join()函数让主线程阻塞,return会直接结束该进程(因为是main函数,在这里相当于exit,会直接退出进程)对应的子线程也会全部结束,如果使用pthread_exit,只会结束当前主线程,并不会结束还没执行完任务的两个线程。这就好比,下班时间规定是六点半,但是你实际下班时间是八点,那么你的主线程使用的就是pthread_exit,干完活的走,没干完活的继续干。使用return的话,相当于六点半到点之后,公司直接让所有人下班回家并关闭大门。
(2)创建线程时使用的句柄:pthread_t类型的参数,创建之后的值是线程的id,与在创建的子线程中使用pthread_self拿到的值是一个值。
(3)还有几个函数未解释,后面再说,return了