1 线程间通信
线程间无需特别的手段进行通信,由于线程间能够共享数据结构,也就是一个全局变量能够被两个线程同一时候使用。只是要注意的是线程间须要做好同步,一般用mutex。线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。
线程的基本概念
线程的定义:
线程也被称为轻量进程(LWP)计算机科学术语,指运行中的程序的调度单位。线程是进程中的实体,一个进程可以拥有多个线程,一个线程必须有一个父进程。线程不拥有系统资源,只有运行必须的一些数据结构;它与父进程的其它线程共享该进程所拥有的全部资源。线程可以创建和撤消线程,从而实现程序的并发执行。一般,线程具有就绪、阻塞和运行三种基本状态。
在多中央处理器的系统里,不同线程可以同时在不同的中央处理器上运行,甚至当它们属于同一个进程时也是如此。大多数支持多处理器的操作系统都提供编程接口来让进程可以控制自己的线程与各处理器之间的关联度。
多线程的概念:线程是程序中完成一个独立任务的完整执行序列,即一个可调度的实体;进程相当于运行中程序的一种抽象。根据运行环境的调度者的身份,线程可分为内核线程和用户线程。内核线程,在有的系统上称为LWP(Light Weight Process,轻量级线程),运行在内核空间,由内核调度;用户线程运行在用户空间,由线程库来调度。当进程的一个内核线程获得CPU的使用权时,它就加载并运行一个用户线程。可见,内核线程相当于用户线程运行的‘容器’,一个进程可以拥有M个内核线程和N个用户线程,其中M<=N,并且一个系统的所有进程中,M和N的比值是固定的。
2 线程控制函数
(1) pthread_create
#include <pthread.h>
int pthread_create(pthread_t * tidp, const pthread_attr_t *attr, void *(*start_rtn)(void *), void *arg);
// 返回:成功返回0,出错返回错误编号
pthread_create (thread, attr, start_routine, arg) 在这里,pthread_create 创建一个新的线程,并让它可执行。下面是关于参数的说明:
参数说明
参数 说明
thread 指向线程标识符指针。
attr 一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL。
start_routine 线程运行函数起始地址,一旦线程被创建就会执行。
arg 运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。
创建线程成功时,函数返回 0,若返回值不为 0 则说明创建线程失败。
调用举例:
- pthread_t tid1;
- // 线程运行函数起始地址,一旦线程被创建就会执行。
- void * thread_fun(void * arg);
- int err;
- err=pthread_create(&tid1,NULL,thread_fun,NULL); //方式1
- pthread_create(&tid1,NULL,thread_fun, (void *)0);//方式2
(2) pthread_exit
#include <pthread.h>
void pthread_exit(void *rval_ptr);
// 线程终止
线程在结束时最好调用该函数,以确保安全、干净的退出。pthread_exit函数通过rval_ptr参数向调用线程的回收者传递退出信息,进程中的其他线程可以调用pthread_join函数访问到这个指针。pthread_exit执行完后不会返回到调用者,而且永远不会失败。
线程可以通过以下三种方式退出,在不终止整个进程的情况下停止它的控制流:
• 线程只是从启动过程中退出,返回值是线程的退出码
• 线程可以被同一进程中的其他线程取消
• 线程调用pthread_exit
调用举例:pthread_exit((void *)2);
(3) pthread_join
#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
// 返回:成功返回0,出错返回错误代码
thread是目标线程标识符,rval_ptr指向目标线程返回时的退出信息,该函数会一直阻塞,直到被回收的线程结束为止。可能的错误码为:
调用举例:pthread_join(tid1, NULL);
(4) pthread_cancel
#include <pthread.h>
int pthread_cancel(pthread_t thread);
// 返回:成功返回0,出错返回错误代码
默认情况下,pthread_cancel函数会使有thread标识的线程的表现为如同调用了参数为PTHREAD_CANCEL的pthread_exit函数,但是,接收到取消请求的目标线程可以决定是否允许被取消以及如何取消,这分别由以下两个函数来控制:
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldstate);
注意pthread_cancel并不等待线程结束,它只是提出请求。
实例1 创建一个简单的线程
//功能:创建一个简单的线程
#include <stdio.h>
#include <pthread.h>
void *mythread1(void)
{
int i;
for(i = 0; i < 10; i++)
{
printf("This is the 1st pthread,created by xiaoqiang!\n");
sleep(1);
}
}
void *mythread2(void)
{
int i;
for(i = 0; i < 10; i++)
{
printf("This is the 2st pthread,created by xiaoqiang!\n");
sleep(1);
}
}
int main(int argc, const char *argv[])
{
int i = 0;
int ret = 0;
pthread_t id1,id2;
ret = pthread_create(&id1, NULL, (void *)mythread1,NULL);
if(ret)
{
printf("Create pthread error!\n");
return 1;
}
ret = pthread_create(&id2, NULL, (void *)mythread2,NULL);
if(ret)
{
printf("Create pthread error!\n");
return 1;
}
pthread_join(id1,NULL);
pthread_join(id2,NULL);
return 0;
}
实例2 向新的线程传递整形值
//功能:向新的线程传递整形值
#include <stdio.h>
#include <pthread.h>
void *create(void *arg)
{
int *num;
num = (int *)arg;
printf("Create parameter is %d\n",*num);
return (void *)0;
}
int main(int argc, const char *argv[])
{
pthread_t id1;
int error;
int test = 4;
int *attr = &test;
error = pthread_create(&id1,NULL,create,(void *)attr);
if(error)
{
printf("Pthread_create is not created!\n");
return -1;
}
sleep(1);
printf("Pthread_create is created..\n");
return 0;
}
实例3 向新建的线程传递字符串
//程序功能:向新建的线程传递字符串
#include <stdio.h>
#include <pthread.h>
void *create(char *arg)
{
char *str;
str = arg;
printf("The parameter passed from main is %s\n",str);
return (void *)0;
}
int main()
{
int error;
pthread_t id1;
char *str1 = "Hello ,xiaoqiang!";
char *attr = str1;
error = pthread_create(&id1, NULL, create, (void *)attr);
if(error != 0)
{
printf("This pthread is not created!\n");
return -1;
}
sleep(1);
printf("pthread is created..\n");
return 0;
}