Linux多线程----直接上代码----线程创建、终止(二)

本文秉承文章一(http://blog.csdn.net/a15261893837/article/details/77103024)所说进行书写。重点突出代码,代码与理论结合进行讲述。

在本文中将重点引用《Unix环境高级编程》第三版的代码进行讲述。将文中代码在Linux环境下运行,分析运行结果;还将引用其他博客的一些代码,以提供尽可能多的示例进行讲述。《Unix环境高级编程》网上有源代码可以下载,下载的代码有个apue.h文件是作者写的一个文件系统,系统不自带,其中包括常用头文件、出错处理函数的定义。apue.h放在apue.3e/threads中。第二版的源代码是文件apue.2e/threads。

下面给出配置apue.h方法,第一种方法是从网上找的,第二种方法是自己配置方法;

1、从网上查看配置方法,有很多这里给一个链接http://4247601.blog.51cto.com/4237601/1548616;

2、将apue.3e/include/下的apue.h复制到/usr/include下,将apue.3e/lib/error.c复制到/usr/include下;同时将代码中的#include"apue.h"改为#include<apue.h>;

本文内容概要:

一、线程创建;

二、线程终止;


Start:

一、线程创建;

线程创建函数在第一篇中已经说了。这里再一次简述一下。

线程创建:pthread_create()函数;

参数个数四个依次为线程ID、线程属性、线程函数起始地址、线程函数参数;

代码如下:

//说明代码时以vim打开的文件为根据,因vim中代码带有行号。

源代码名称:threadid.c

#include<stdlib.h>
#include <apue.h>
#include <pthread.h>
pthread_t ntid;

void
printids(const char *s)
{
	pid_t		pid;
	pthread_t	tid;

	pid = getpid();
	tid = pthread_self();
	printf("%s pid %lu tid %lu (0x%lx)\n", s, (unsigned long)pid,
	  (unsigned long)tid, (unsigned long)tid);
}

void *
thr_fn(void *arg)
{
	printids("new thread: ");
	return((void *)0);
}

int
main(void)
{
	int		err;

	err = pthread_create(&ntid, NULL, thr_fn, NULL);
	if (err != 0)
		err_exit(err, "can't create thread");
	printids("main thread:");
	sleep(1);
	exit(0);
}

代码运行结果如下:


图一.代码运行结果

图一为代码运行结果。屏幕左侧为代码,右侧为Shell指令及结果。

分屏采用的是tmux。下面简单说一下tmux分屏安装及常用命令。

安装:sudo apt-get install tmux

常用命令:

Ctrl+b " - split pane horizontally
Ctrl+b % - 将当前窗格垂直划分
Ctrl+b 方向键 - 在各窗格间切换
Ctrl+b,并且不要松开Ctrl,方向键 - 调整窗格大小
Ctrl+b c - (c)reate 生成一个新的窗口
Ctrl+b n - (n)ext 移动到下一个窗口
Ctrl+b p - (p)revious 移动到前一个窗口.
Ctrl+b 空格键 - 采用下一个内置布局 
Ctrl+b q - 显示分隔窗口的编号 
Ctrl+b o - 跳到下一个分隔窗口 
Ctrl+b & - 确认后退出 tmux 

tmux所有自带命令都默认需要先按Ctrl + b,然后再键入对应的命令。

实践出真知。首先在Shell中输入tmux后;然后Ctrl + b,紧接着%;最终神奇的一幕出现了。本文中左屏幕用来显示代码,右侧屏幕输入指令;

下面说明一下屏幕右侧内容:

编译代码指令:gcc threadid.c -lpthread;

然后ls列出文件,可以看出生成了a.out;然后输入./a.out

显示了程序结果:


代码36行sleep函数;这里主线程要休眠;否则如果主线程退出了;新的线程还没来得及执行,整个进程就结束了。读者可以将36行注释掉再运行一遍程序就会发现运行结果只有main thread那一行。

32行:如果新线程创建成功就返回0;那么err就等于0.所里33-34行就一目了然了。第一参数ntid就是新创建线程的ID;第二个参数代码新新城属性,这里为NULL代表默认属性;第三个参数thr_fn为新线程函数;第四个参数NULL代表thr_fn函数传入参数。

15行:pthread_self()函数返回线程的ID。

现在整个程序思路就理顺了。

二、线程终止;

源代码:exitstatus.cpp

#include <apue.h>
#include <pthread.h>
#include<iostream>
using namesace std;
void *
thr_fn1(void *arg)
{
printf("thread 1 returning\n");
return((void *)1);
}


void *
thr_fn2(void *arg)
{
printf("thread 2 exiting\n");
pthread_exit((void *)2);
}


int
main(void)
{
int err;
pthread_t tid1, tid2;
void *tret;


err = pthread_create(&tid1, NULL, thr_fn1, NULL);
if (err != 0)
err_exit(err, "can't create thread 1");
err = pthread_create(&tid2, NULL, thr_fn2, NULL);
if (err != 0)
err_exit(err, "can't create thread 2");
err = pthread_join(tid1, &tret);
if (err != 0)
err_exit(err, "can't join with thread 1");
printf("thread 1 exit code %ld\n", (long)tret);
err = pthread_join(tid2, &tret);
if (err != 0)
err_exit(err, "can't join with thread 2");
printf("thread 2 exit code %ld\n", (long)tret);
exit(0);
}
Linux代码运行如下:


图二. 线程终止

图二显示了程序运行结果。注意这里是.cpp文件。需要用g++编译。

Shell指令:g++ exitstatus.cpp -o ga -lpthread(顺便补充一下-lpthread是链接需要)

可以生成ga

然后执行./ga;程序结果如下:


void *则为“无类型指针”,可以指向任何数据类型,void指针可以指向任意类型的数据,亦即可用任意数据类型的指针对void指针赋值。

L21-L26(这里用L代表行):这里创建了两个新线程,如果线程创建失败,输出can't create thread 1 or 2.

L14:pthread_exit(void*rval_ptr)函数,头文件pthread.h。rval_ptr是无类型指针。pthread_join()函数可以访问到该指针。

L28:pthread_join(pthread_t thread,void **rval_ptr)函数,在头文件pthread.h中.thread代表线程ID,rval_ptr代表线程返回码,就是pthread_exit函数的指针。调用线程被阻塞,直到指定线程thread调用pthread_exit()、从启动历程中返回或者被取消。L31打印出了线程1的返回码1。L28属于调用从启动历程中返回的指针,这里是(void*)1.

L32-L35:这次pthread_join()调用的是pthread_exit()函数的返回函数指针,打印为2.

pthread_join()函数调用线程一直被阻塞,直到线程退出。为了验证这个说法。本文在L13行前增加一个sleep()函数。看一看打印结果。

#include<iostream>
#include <apue.h>
#include <pthread.h>

using namespace std;
void *
thr_fn1(void *arg){
	printf("thread 1 returning\n");
	return((void *)1);	
}
void *
thr_fn2(void *arg){
	while(1){
	sleep(1);
}
	printf("thread 2 exiting\n");
	pthread_exit((void *)2);
}
int
main(void){
	int			err;
	pthread_t	tid1, tid2;
	void		*tret;
	err = pthread_create(&tid1, NULL, thr_fn1, NULL);
	if (err != 0)
		err_exit(err, "can't create thread 1");
	err = pthread_create(&tid2, NULL, thr_fn2, NULL);
	if (err != 0)
		err_exit(err, "can't create thread 2");
	
	err = pthread_join(tid1, &tret);
	if (err != 0)
		err_exit(err, "can't join with thread 1");
	printf("thread 1 exit code %ld\n", (long)tret);
	err = pthread_join(tid2, &tret);
	if (err != 0)
		err_exit(err, "can't join with thread 2");
	printf("thread 2 exit code %ld\n", (long)tret);
	
	cout<<"shh does the change"<<endl;
	exit(0);
}


图三. 线程阻塞程序

L13-L14:通过增加sleep函数,可以通过右侧屏幕打印结果看出,线程2一直被阻塞,而线程1没有受到任何影响。由于阻塞导致shh does the change都没有打印出来。下面对程序做进一步修改。将线程2阻塞函数去掉。

#include<iostream>
#include <apue.h>
#include <pthread.h>

using namespace std;
void *
thr_fn1(void *arg){
	printf("thread 1 returning\n");
	return((void *)1);	
}
void *
thr_fn2(void *arg){
	while(1){
	sleep(1);
}
	printf("thread 2 exiting\n");
	pthread_exit((void *)2);
}
int
main(void){
	int			err;
	pthread_t	tid1, tid2;
	void		*tret;
	err = pthread_create(&tid1, NULL, thr_fn1, NULL);
	if (err != 0)
		err_exit(err, "can't create thread 1");
	err = pthread_create(&tid2, NULL, thr_fn2, NULL);
	if (err != 0)
		err_exit(err, "can't create thread 2");
	
	err = pthread_join(tid1, &tret);
	if (err != 0)
		err_exit(err, "can't join with thread 1");
	printf("thread 1 exit code %ld\n", (long)tret);
	/*err = pthread_join(tid2, &tret);
	if (err != 0)
		err_exit(err, "can't join with thread 2");
	printf("thread 2 exit code %ld\n", (long)tret);*/
	
	cout<<"shh does the change"<<endl;
	exit(0);
}


图四.取消线程2阻塞

从图四可以看出shh does the change顺利打印出来。线程2阻塞没用影响到线程1和主线程的结果。为了保险起见最好在L40后添加一个sleep函数防止主线程过早退出。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值