Linux下C语言的多线程编程学习
一、首先,简单了解一下多线程,从耳熟能详的fork()、pthread中理点头绪出来,然后自己写一个简单的来增加一下信心。
1、Linux系统下的多线程遵循POSIX线程接口,称为pthread。编写Linux下的多线程程序,需要使用头文件pthread.h,连
接时需要使用库libpthread.a。因此,后面的编译必须在选项中加入 -lpthread
选项,否则提示找不到pthread_create()这些函数。
2、pthread_t
是一个线程的标识符,创建线程用pthread_create(),等待线程结束用pthread_join(),这样,差不多就可以开始写第一个简单的多线程程序了,简单得类似HelloWorld
下面的是我自己写的一个最简单的程序。
///
simpleone.c
1 #i nclude
2 #i nclude
34 void thread()
5 {
6 int i;
7 for (i=0;i<3;i++)
8 {
9 printf("This is thread %d .\r\n",i);
10 sleep(i);
11 }
12 }
13 14 int main()
15 {
16 pthread_t id;
17 int i,ret;
18 ret = pthread_create(&id,NULL,(void *)thread,NULL);
19 if (ret != 0)
20 {
21 printf("Create thread error!\r\n");
22 exit(1);
23 }
24 for (i=0;i<3;i++)
25 {
26 printf("This is the main thread %d .\r\n",i);
27 sleep(i);
28 }
29 pthread_join(id,NULL);
30 return(0);
31 }
32
使用gcc -g -lpthread simpleone.c 编译
使用./a.out运行
结果:
This is thread 0 .
This is thread 1 .
This is the main thread 0 .
This is the main thread 1 .
This is thread 2 .
This is the main thread 2 .
不同的机器运行结果有可能不同,是由于两个“并行”的线程抢夺处理器资源造成的。而sleep(i)是我自作聪明的想法,仅仅是为了让结果看上去更加能体现两个线程是“并行”执行的,其实完全可以省去。
线程属性:是否绑定、是否分离、堆栈地址、堆栈大小、优先级
默认的属性:非绑定、非分离、缺省1M的堆栈、与父进程同样级别的优先级。
########################
#######绑定轻进程#######
########################
关于线程的绑定,牵涉到另外一个概念:轻进程(LWP:Light Weight Process)。
轻进程可以理解为内核线程,它位于用户层和系统层之间。系统对线程资源的分配、对线程的控制是通过轻进程来实现的,一个轻进程可以控制一个或多个线程。默
认状况下,启动多少轻进程、哪些轻进程来控制哪些线程是由系统来控制的,这种状况即称为非绑定的。绑定状况下,则顾名思义,即某个线程固定的"绑"在一个轻进程之上。被绑定的线程具有较高的响应速度,这是因为CPU时间片的调度是面向轻进程的,绑定的线程可以保证在需要的时候它总有一个轻进程可用。通过设置被绑定的轻进程的优先级和调度级可以使得绑定的线程满足诸如实时反应之类的要求。
#i nclude
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_create(&tid, &attr, (void *) my_function,
NULL);
########################
######设置分离状态######
########################
线程的分离状态决定一个线程以什么样的方式来终止自己。线程的默认属性下,即为非分离状态,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。而分离线程不是这样子的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。程序员应该根据自己的需要,选择适当的分离状态。设置线程分离状态的函数为pthread_attr_setdetachstate(pthread_attr_t
*attr, int detachstate)。第二个参数可选为PTHREAD_CREATE_DETACHED(分离线程)和
PTHREAD
_CREATE_JOINABLE(非分离线程)。这里要注意的一点是,如果设置一个线程为分离线程,而这个线程运行又非常快,它很可能在pthread_create函数返回之前就终止了,它终止以后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用pthread_cond_timewait函数,让这个线程等待一会儿,留出足够的时间让函数pthread_create返回。设置一段等待时间,是在多线程编程里常用的方法。但是注意不要使用诸如wait()之类的函数,它们是使整个进程睡眠,并不能解决线程同步的问题。
########################
#######设置优先级#######
########################
另外一个可能常用的属性是线程的优先级,它存放在结构sched_param中。用函数pthread_attr_getschedparam和函数pthread_attr_setschedparam进行存放,一般说来,我们总是先取优先级,对取得的值修改后再存放回去。下面即是一段简单的例子。
#i nclude
#i nclude
pthread_attr_t attr;
pthread_t tid;
sched_param param;
int newprio=20;
pthread_attr_init(&attr);
pthread_attr_getschedparam(&attr, ¶m);
param.sched_priority=newprio;
pthread_attr_setschedparam(&attr, ¶m);
pthread_create(&tid, &attr, (void *)myfunction, myarg);
About Mutex
mutex是一个互斥锁对象,互斥锁是为了防止多线程同时修改某一公共资源,我在下面的程序里把它“锁”在了一个叫buffer[10]的缓冲区
上,模型是2个Reader和2个Writer,Reader要等到叫buffer的书架上有书的时候才可以read,而Writer也必须在书架没有放
满的情况下才可以把新写的书放到书架上。我的程序里书架的大小是1,当然也可以设置书架的大小,不过实现过程大同小异。就不多说了。来看程序:
1 #i nclude
2 #i nclude
34 void reader_function(void);
5 void writer_function(void);
6
7 char buffer[10]={0};
8 int buffer_has_item=0;
9 pthread_mutex_t mutex;
10
11 int main(void)
12 {
13 pthread_t reader;
14
15 16 pthread_mutex_init (&mutex,NULL);
17 pthread_create(&reader,NULL, (void *)reader_function,
NULL);
18 writer_function();
19 }
20
21 void writer_function(void)
22 {
23 int i,ti;
24
25 for(i=1;i<3;)
26 {
27 ti=i;
28 29 pthread_mutex_lock(&mutex);
30 printf("Writer %d Locked Buffer.\r\n",i);
31 if (buffer_has_item==0)
32 {
33 buffer_has_item=1;
34