第二组 线程创建与管理与线程通信
1 题目
1. 线程创建与管理
查阅 Linux 和 Pthread 线程库相关资料,参照相关示例程序,设计父进程/线程和子线程的业务处理逻辑;利用 pthread_create
、pthread_exit
、pthread_cancel
、pthread_join
、pthread_self
等线程管理函数,创建和管理线程,观察父子进程/线程的结构和并发行为,掌握等待、退出、撤销等线程控制方法。
要求:
-
在一个进程内创建多个子线程(如不少于 3 个子线程),父子子线程具有各自不同的业务处理逻辑,子线程执行自身特定的线程函数。父子线程间通过
pthread_join()
函数实现同步和资源释放; -
一个进程内的多个子线程分别以不同方式终止或退出执行,如通过
pthread_exit()
和return
自己主动终止,或被被其它线程通过pthread_cancel
被动终止,观察对比以不同方式退出执行的子线程的行为差异; -
在创建的父子进程/线程代码中的不同位置处增加数十到数百毫秒的随机延迟(使用
sleep()
),使得进程和线程的执行横跨多个时间片,保证线程执行时间不少于 3 个时间片。
2. 线程通信
属于同一个进程中的多个线程使用相同的地址空间,共享大部分数据,一个线程的数据可以直接为其它线程所用,这些线程相互间可以方便快捷地利用共享数据结构进行通信。
编写程序,创建线程,实现主线程与子线程间、子线程相互间通过共享数据类型,如整型变量、字符串、结构体等传递信息,进行通信。
2 实验目的
- 理解线程的概念
- 掌握在 linux 下创建线程的基本方法
- 掌握LINUX下线程通信的方法
3 实验内容
3.1 实验一
POSIX线程(POSIX threads),简称Pthreads,是线程的POSIX标准。因为pthread并非Linux系统的默认库,而是POSIX线程库。在Linux中将其作为一个库来使用,因此加上 -lpthread(或-pthread)以显式链接该库,POSIX标准定义了创建和操纵线程的一整套API。在类Unix操作系统(Unix、Linux、Mac OS X等)中,都使用Pthreads作为操作系统的线程。
3.2 实验二
线程间通信分为两种情况:
- 分属于不同进程的线程间的通信。可以采用进程间通信机制,如消息队列;
- 位于同一进程内的不同线程间的通信。此时,线程可以通过共享的进程全局数据结构进行快速通信,但需要考虑采用合适的同步互斥机制,以保证访问结果的正确,这类似于进程间的同步与互斥。
4 实验设计原理
4.1 实验一
函数 | 传入参数 | 返回值 | 作用 |
---|---|---|---|
pthread_create | (pthread_t *thread,pthread_attr_t*attr,void(start_routine)(void ), void\arg)thread :指向所创建线程的标识符的指针,线程创建成功时,返回被创建线程的 ID。attr :用于指定被创建线程的属性,NULL 表示使用默认属性。start_routine : 函数指针 ,指向线程创建后要调用的函数,是一个以指向 void的指针作为参数和返回值的函数指针,这个被线程调用的函数也被称为线程函数。arg :指向传递给线程函数的参数 |
创建成功:0创建失败:返回错误码 | 创建线程 |
pthread_exit | retval:线程退出时的返回值,可被 pthread_join()等其它函数获取 | 终止进程内特定线程 | |
pthread_join | (pthread_t thread,void **thread_return)thread :等待退出的线程 ID。thread_return :用于定义的指针,存储被等待线程结束时的返回值(不为 NULL 时) |
等待成功:0。等待失败:返回错误码 | 实现线程同步和资源释放。将当前进程挂起来等待线程的结束。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回 |
分别创建三个子线程,一个进程内的多个子线程分别以不同方式终止或退出执行,通过 pthread_exit()
和return
自己主动终止,或被其它线程通过pthread_cancel
被动终止
4.2 实验二
线程间通讯可以通过pthread_create
函数中的参数传递,或者是通过全局变量来进行访问修改参数(如果有多个线程对参数进行访问需要加锁)
分别写了三个进程,其中sendChar
线程接收字符串,sendStruct
线程接收结构体变量,getData
线程访问全局变量并进行修改。
由于传递过来的参数是void*
类型,需要先强制转换为指定的数据类型
5 实验步骤
5.1 实验一
在vim文本编译器里编写代码
thread.c部分代码
编译执行
gcc thread_manage.c -o thread_manage -lpthread
运行程序
5.2 实验二
在vim文本编译器里编写代码
ITC.c部分代码
编译执行
gcc ITC.c -o ITC -lpthread
运行结果
6 实验结果及分析
6.1 实验一
- 使用
pthread_exit()
函数退出的线程,线程返回值为pthread_exit
指定的参数; - 使用
return
自然退出的线程,使用thread_join
查看线程返回值则为return结果 - 在主线程里调用
pthread_cancel
可以强制中止线程的结束
6.2 实验二
实验分析:
-
数据通过
pthread_create
函数的参数从主线程传递到创建的新线程中,无论该数据是字符串还是用户自定义的结构体变量。 -
使用全局变量进行数据传递,在新创建的线程中修改全局变量后,主线程也可以得到改变后的全局变量的值。
7 程序代码
7.1 实验一
#include<pthread.h>
#include<stdio.h>
#include <stdio.h>
#include <sys/select.h>
static void sleep_ms(unsigned int secs)//实现ms级别的sleep
{
struct timeval tval;
tval.tv_sec = secs / 1000;
tval.tv_usec = (secs * 1000) % 1000000;
select(0, NULL, NULL, NULL, &tval);
}
void* thread_1(void* arg) {//exit退出
int i;
for (i = 0; i < 4; i++)
{
printf("now running thread [1] ID:%d\n", (unsigned int)pthread_self());
sleep_ms(50);
}
pthread_exit((void*)1);
}
void* thread_2(void* arg) {//正常执行完毕退出
int j;
for (j = 0; j < 4; j++)
{
sleep_ms(345);
printf("now running thread [2] ID:%d\n", (unsigned int)pthread_self());
}
return 2;
}
void* thread_3(void* arg) {//cancel
int k;
for (k = 0; k < 4; k++)
{
printf("now running thread [3] ID:%d\n", (unsigned int)pthread_self());
sleep_ms(789);
}
}
int main() {
int res = 0;
void* code1, * code2, * code3;
pthread_t thread1, thread2, thread3;
/*线程1pthread_exit*/
res = pthread_create(&thread1, NULL, (void*)thread_1, NULL);
if (res != 0) {
printf("create thread 1 failed\n");
return -1;
}
res = pthread_join(thread1, &code1);
if (res) {
printf("thread 1 is not exit\n ");
return -2;
}
printf("The exit of thread 1 is %d\n", (int)code1);
/*线程2 正常return*/
res = pthread_create(&thread2, NULL, (void*)thread_2, NULL);
if (res != 0) {
printf("create thread 2 failed\n");
return -1;
}
pthread_join(thread2, &code2);
if (res) {
printf("thread 2 is not exit\n ");
return -2;
}
printf("The exit of thread 2 is %d\n", (int)code2);
/*线程3 cancel被迫中止*/
res = pthread_create(&thread3, NULL, (void*)thread_3, NULL);
if (res != 0) {
printf("create thread 2 failed\n");
return -1;
}
sleep_ms(50);
res = pthread_cancel(thread3);
if (res != 0) {
printf("fail to cancel thread3\n");
}
res = pthread_join(thread3, &code3);
if (res != 0) {
printf("fail to join thread3\n");
return 0;
}
if (code3 == PTHREAD_CANCELED) {
printf("thread3 is canceled\n");
printf("The exit of thread 3 is %d\n", (int)code3);
}
else {
printf("error\n");
}
return 0;
}
7.2 实验二
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
static int a = 5;
typedef struct member
{
int a;
char* s;
}member;
void* sendChar(char* arg)
{
char* str;
str = arg;
printf("=========\n");
printf("now running thread sendChar\n");
printf("The parameter passed from main is %s\n", str);
return (void*)0;
}
void* sendStruct(void* arg)
{
member* recv;
member* send;
recv = (member*)arg;
printf("=========\n");
printf("now running thread sendStruct\n");
printf("menber->a = %d\n", recv->a);
printf("menber->s = %s\n", recv->s);
send = (member*)malloc(sizeof(member));
send->a = recv->a * 2;
send->s = "Jack";
return (void*)send;
}
void* getData(void* arg)
{
printf("=========\n");
printf("now running thread getData\n");
printf("New pthread...\n");
printf("a = %d\n", a);
a = 3;
return (void*)0;
}
int main()
{
int error;
pthread_t id1, id2, id3;
char* str1 = "Hello!";
char* attr = str1;
error = pthread_create(&id1, NULL, sendChar, (void*)attr);
if (error != 0)
{
printf("This pthread is not created!\n");
return -1;
}
sleep(1);
printf("pthread is created..\n");
member* p;
void* get;
p = (member*)malloc(sizeof(member));
p->a = 1;
p->s = "Robben!";
error = pthread_create(&id2, NULL, sendStruct, (void*)p);
if (error)
{
printf("pthread is not created!\n");
return -1;
}
sleep(1);
printf("pthread is created!\n");
pthread_join(id2, &get);
printf("member->a=%d\n", ((member*)get)->a);
printf("member->s=%s\n", ((member*)get)->s);
free(p);
p = NULL;
error = pthread_create(&id3, NULL, getData, NULL);
if (error != 0)
{
printf("new thread is not created!\n");
return -1;
}
sleep(1);
printf("New thread is created...\n");
printf("the data change into %d\n", a);
return 0;
}
Comments NOTHING