linux下C语⾔多线程编程实例⽤⼀个实例。来学习linux下C语⾔多线程编程实例。
代码⽬的:通过创建两个线程来实现对⼀个数的递加。
代码:
//包含的头⽂件
#include <pthread.h>
#include <stdio.h>
#include <sys/time.h>
#include <string.h>
#define MAX 10
pthread_t thread[2]; //两个线程
pthread_mutex_t mut;
int number=0;
int i;
void *thread1()
{
printf ("thread1 : I'm thread 1/n");
for (i = 0; i < MAX; i++) //模拟线程执⾏时间
{
printf("thread1 : number = %d/n",number);
pthread_mutex_lock(&mut);
number++;
pthread_mutex_unlock(&mut);
sleep(2);
}
printf("thread1 :主函数在等我完成任务吗?/n");
pthread_exit(NULL);
}
void *thread2()
{
printf("thread2 : I'm thread 2/n");
for (i = 0; i < MAX; i++)
{
printf("thread2 : number = %d/n",number);
pthread_mutex_lock(&mut);
number++;
pthread_mutex_unlock(&mut);
sleep(3);
}
printf("thread2 :主函数在等我完成任务吗?/n");
pthread_exit(NULL);
}
void thread_create(void) //创建两个线程
{
int temp;
memset(&thread, 0, sizeof(thread)); //comment1
/*创建线程*/
if((temp = pthread_create(&thread[0], NULL, thread1, NULL)) != 0) //comment2
printf("线程1创建失败!/n");
else
printf("线程1被创建/n");
if((temp = pthread_create(&thread[1], NULL, thread2, NULL)) != 0) //comment3
printf("线程2创建失败");
else
printf("线程2被创建/n");
}
void thread_wait(void)
{
/*等待线程结束*/
if(thread[0] !=0)
{ //comment4
pthread_join(thread[0],NULL);
linux下的sleep函数printf("线程1已经结束/n");
}
if(thread[1] !=0)
{
//comment5
pthread_join(thread[1],NULL);
printf("线程2已经结束/n");
}
}
int main()
{
/*⽤默认属性初始化互斥锁*/
pthread_mutex_init(&mut,NULL);
printf("我是主函数哦,我正在创建线程,呵呵/n");
thread_create();
printf("我是主函数哦,我正在等待线程完成任务阿,呵呵/n");
thread_wait();
return 0;
}
下⾯我们先来编译、执⾏⼀下
引⽂:
falcon@falcon:~/program/c/code/ftp$ gcc -lpthread -o thread_example thread_example.c
falcon@falcon:~/program/c/code/ftp$ ./thread_example
我是主函数哦,我正在创建线程,呵呵
线程1被创建
线程2被创建
我是主函数哦,我正在等待线程完成任务阿,呵呵
thread1 : I'm thread 1
thread1 : number = 0
thread2 : I'm thread 2
thread2 : number = 1
thread1 : number = 2
thread2 : number = 3
thread1 : number = 4
thread2 : number = 5
thread1 : number = 6
thread1 : number = 7
thread2 : number = 8
thread1 : number = 9
thread2 : number = 10
thread1 :主函数在等我完成任务吗?
线程1已经结束
thread2 :主函数在等我完成任务吗?
线程2已经结束
实例代码⾥头的注释应该⽐较清楚了吧,下⾯我把⽹路上介绍上⾯涉及到的⼏个函数和变量给引⽤过来。引⽂:
线程相关操作
⼀ pthread_t
pthread_t在头⽂件/usr/include/bits/pthreadtypes.h中定义:
typedef unsigned long int pthread_t;
它是⼀个线程的标识符。
⼆ pthread_create
函数pthread_create⽤来创建⼀个线程,它的原型为:
extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr,
void *(*__start_routine) (void *), void *__arg));
第⼀个参数为指向线程标识符的指针,第⼆个参数⽤来设置线程属性,第三个参数是线程运⾏函数的起始地址,最后⼀个参数是运⾏函数的参数。这⾥,我们的函数thread不需要参数,所以最后⼀个参数设为空指针。第⼆个参数我们也设为空指针,这样将⽣成默认属性的线程。对线程属性的设定和修改我们将在下⼀节阐述。当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL。前者表⽰系统限制创建新的线程,例如线程数⽬过多了;后者表⽰第⼆个参数代表的线程属性值⾮法。创建线程成功后,新创建的线程则运⾏参数三和参数四确定的函数,原来的线程则继续运⾏下⼀⾏代码。
三 pthread_join pthread_exit
函数pthread_join⽤来等待⼀个线程的结束。函数原型为:
extern int pthread_join __P ((pthread_t __th, void **__thread_return));
第⼀个参数为被等待的线程标识符,第⼆个参数为⼀个⽤户定义的指针,它可以⽤来存储被等待线程的返回值。
这个函数是⼀个线程阻塞的函数,调⽤它的函数将⼀直等待到被等待的线程结束为⽌,当函数返回时,被等待线程的资源被收回。⼀个线程的结束有两种途径,⼀种是象我们上⾯的例⼦⼀样,函数结束了,调⽤它的线程也就结束了;
另⼀种⽅式是通过函数pthread_exit来实现。它的函数原型为:
extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__));
唯⼀的参数是函数的返回代码,只要pthread_join中的第⼆个参数thread_return不是NULL,这个值将被传递给
thread_return。最后要说明的是,⼀个线程不能被多个线程等待,否则第⼀个接收到信号的线程成功返回,其余调⽤
pthread_join的线程则返回错误代码ESRCH。
在这⼀节⾥,我们编写了⼀个最简单的线程,并掌握了最常⽤的三个函数pthread_create,pthread_join和pthread_exit。下⾯,我们来了解线程的⼀些常⽤属性以及如何设置这些属性。
互斥锁相关
互斥锁⽤来保证⼀段时间内只有⼀个线程在执⾏⼀段代码。
⼀ pthread_mutex_init
函数pthread_mutex_init⽤来⽣成⼀个互斥锁。NULL参数表明使⽤默认属性。如果需要声明特定属性的互斥锁,须调⽤函数pthread_mutexattr_init。函数pthread_mutexattr_setpshared和函数 pthread_mutexattr_settype⽤来设置互斥锁属性。前⼀个函数设置属性pshared,它有两个取值, PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED。前者⽤来不同进程中的线程同步,后者⽤于同步本进程的不同线程。在上⾯的例⼦中,我们使⽤的是默认属性PTHREAD_PROCESS_ PRIVATE。后者⽤来设置互斥锁类型,可选的类型有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、PTHREAD_MUTEX_RECURSIVE和PTHREAD _MUTEX_DEFAULT。它们分别定义了不同的上所、解锁机制,⼀般情况下,选⽤最后⼀个默认属性。
⼆ pthread_mutex_lock pthread_mutex_unlock pthread_delay_np
pthread_mutex_lock声明开始⽤互斥锁上锁,此后的代码直⾄调⽤pthread_mutex_unlock为⽌,均被上锁,即同⼀时间只能被⼀个线程调⽤执⾏。当⼀个线程执⾏到pthread_mutex_lock处时,如果该锁此时被另⼀个线程使⽤,那此线程被阻塞,即程序将等待到另⼀个线程释放此互斥锁。
注意:
1 需要说明的是,上⾯的两处sleep不光是为了演⽰的需要,也是为了让线程睡眠⼀段时间,让线程释放互斥锁,等待另⼀个线程使⽤此锁。下⾯的参考资料1⾥头说明了该问题。但是在linux下好像没有pthread_delay_np那个函数(我试了⼀下,提⽰没有定义该函数的引⽤),所以我⽤了sleep来代替,不过参考资料2中给出另⼀种⽅法,好像是通过pthread_cond_timedwait来代替,⾥头给出了⼀种实现的办法。
2 请千万要注意⾥头的注释comment1-5,那是我花了⼏个⼩时才出的问题所在。
如果没有comment1和comment4,comment5,将导致在pthread_join的时候出现段错误,另外,上⾯的comment2和comment3是根源所在,所以千万要记得写全代码。因为上⾯的线程可能没有创建成功,导致下⾯不可能等到那个线程结束,⽽在⽤
pthread_join的时候出现段错误(访问了未知的内存区)。另外,在使⽤memset的时候,需要包含string.h头⽂件哦
参考资料:
1。Linux下的多线程编程
2。pthread_delay_np(这⾥头有个关于posix条件变量的例⼦)
3。pthread_join和段错误(⾮常感谢这⾥头的哥们,千万要看哦)
4。posix线程编程指南[学习linux下多线程,不看这个你会后悔的]
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论