周梦康 发表于 2015-11-06 2821 次浏览 标签 : Linuxpthread

进程和线程

每个线程都包含有表示执行环境所必需的信息,包括线程ID、一组寄存器值、栈、调度优先级和策略、信号屏蔽字、errno变量以及线程私有数据。一个进程的所有信息对该进程的所有线程是共享的,包括可执行程序的代码、程序的全局内存和堆内存、栈以及文件描述符。

线程标识

线程 id 数据类型pthread_t

#比较两个线程是否为同一个
pthread_equal(pthread_t tid1, pthread_t tid2)

#获取自身的线程id
pthread_self(void);

第二方法还好理解,第一个方法有什么用呢?书上举的这个例子非常好:

有一个队列任务,主线程负责往队列里存放任务,在这个任务的数据结构中标识了一个线程id,只有这个对应的线程id的人才能来处理这个任务,这里就用到了第一个函数。这有点类似于快递分发安排一样,指定了派送员派送哪些快件。

线程创建

线程创建时,并不能保证哪个线程会先运行:是新创建的线程,还是调用线程。

练习:打印进程ID,新线程ID以及初始线程的线程ID(没有使用书上的apue.h头文件)

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.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;

	//新创建的线程从 thr_fn 函数的地址开始运行
	err = pthread_create(&ntid, NULL, thr_fn, NULL);
	if (err != 0)
	{
		perror("创建失败");
	}

	printids("main thread: ");
	sleep(1);
	exit(0);
}

编译的时候会提示

undefined reference to `pthread_create`

问题的原因:pthread不是Linux下的默认的库,也就是在链接的时候,无法找到phread库中哥函数的入口地址,于是链接会失败。

解决:在gcc编译的时候,附加要加-lpthread或者-pthread参数即可解决。

[zhoumengkang@localhost unix]$ gcc print_pthread_id.c  -lpthread
[zhoumengkang@localhost unix]$ ll
总用量 0
-rwxr-xr-x 1 zhoumengkang zhoumengkang 7774 11月  6 2015 a.out
-rw-r--r-- 1 zhoumengkang zhoumengkang  623 11月  6 00:27 print_pthread_id.c
[zhoumengkang@localhost unix]$ ./a.out
main thread:  pid 23465 tid 140351469729536 (0x7fa61f7f3700)
new thread:  pid 23465 tid 140351469721344 (0x7fa61f7f1700)

线程终止

如果进程中的任意线程调用exit,_Exit,_exit,那么整个进程就会终止,单个线程的退出方式(不终止整个进程的情况下):

  1. 线程可以简单地从启动例程中返回,返回值是线程的退出码;

  2. 线程可以被统一进程中的其他线程取消;

  3. 调用pthread_exit.

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <time.h>

void * thr_fn1(void *arg)
{
	printf("time: %d thread 1 start\n", time(0));
	sleep(2);

	printf("time: %d thread 1 return\n", time(0));
	return ((void *)0);
}

void * thr_fn2(void *arg)
{
	printf("time: %d thread 2 start and exit\n", time(0));
	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)
	{
		perror("can't create thread 1");
	}

	err = pthread_create(&tid2, NULL, thr_fn2, NULL);
	if (err != 0)
	{
		perror("can't create thread 1");
	}

	err = pthread_join(tid1, &tret);
	if (err != 0)
	{
		perror("can't join with thread 1");
	}
	printf("time: %d thread 1 exit code %ld\n", time(0), (long) tret);

	err = pthread_join(tid2, &tret);
	if (err != 0)
	{
		perror("can't join with thread 2");
	}
	printf("time: %d thread 2 exit code %ld\n", time(0), (long) tret);

	exit(0);
}

编译打印结果:

[zhoumengkang@localhost unix]$ gcc pthread_exit_demo.c -pthread
[zhoumengkang@localhost unix]$ ./a.out
time: 1446822750 thread 2 start and exit
time: 1446822750 thread 1 start
time: 1446822752 thread 1 return
time: 1446822752 thread 1 exit code 0
time: 1446822752 thread 2 exit code 2

通过测试,发现因为thr_fn1阻塞了2s,所以主线程在执行pthread_join的时候,也一直阻塞,直到tid1从启动例程中返回。在这里tret是无类型指针,所以可以传递包含复杂信息的结构的地址。

线程同步

多线程互斥锁


评论列表