要学习事物,示例通常是最有趣的. 我总是学习基本理论并且不这样做. 我感到没有成就感.
让我们先举一个例子. 我们通过创建两个线程来实现数字的递增.
也许这个例子没有实际价值,但是经过一些修改,我们可以在其他地方使用它来拉动
.
这是我们的代码:
/*thread_example.c : c multiple thread programming in linux
*author : falcon
*E-mail : [email protected]
*/
#include
#include
#include
#include
#define MAX 10
pthread_t thread[2];
pthread_mutex_t mut;
int number=0, 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);
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
我是主要功能linux c多线程编程,我正在等待线程完成任务,哈哈
线程1: 我是线程1
线程1: 数字= 0
线程2: 我是线程2
线程2: 数字= 1
线程1: 数字= 2
thread2: 数字= 3
线程1: 数字= 4
thread2: 数字= 5
线程1: 数字= 6
线程1: 数字= 7
thread2: 数字= 8
线程1: 数字= 9
thread2: 数字= 10
线程1: 主要功能正在等待我完成任务吗?
线程1已经结束
thread2: 主要功能正在等待我完成任务吗?
线程2已结束
示例代码中的注释应该更清楚. 下面,我将引用Internet上上面提到的几个函数和变量.
报价:
与线程相关的操作
一个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));
第一个参数是指向线程标识符的指针,第二个参数用于设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数. 在这里,我们的函数线程不需要参数,因此最后一个参数设置为空指针. 我们还将第二个参数设置为空指针,这将生成具有默认属性的线程. 下一节将说明线程属性的设置和修改. 成功创建线程后,该函数返回0. 如果不为0,则线程创建失败. 常见的错误返回码为EAGAIN和EINVAL. 前者意味着系统限制了新线程的创建,例如,线程数太多;后者意味着第二个参数表示的线程属性值是非法的. 成功创建线程后,新创建的线程将运行由参数3和参数4确定的功能,而原始线程将继续运行下一行代码.
三个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应该注意的是,以上两个睡眠不仅用于演示目的,还用于使线程休眠一段时间,允许线程释放互斥锁并等待另一个线程使用该锁. . 以下参考资料1解释了该问题. 但是在Linux下,似乎没有pthread_delay_np函数(我尝试过,并且没有对定义的函数的引用),所以我改用sleep方法,但是参考2中提供了另一种方法,该方法似乎已由pthread_cond_timedwait代替. ,为实现该目标提供了一种方法.
2请务必注意其中的注释1-5. 我花了几个小时才找出问题所在.
如果没有comment1和comment4,comment5,则会在pthread_join中导致分段错误. 另外,上面的comment2和comment3是根本原因,因此请记住编写完整的代码. 由于上面的线程可能无法成功创建,因此无法等待该线程结束,并且在使用pthread_join时会发生段错误(访问未知内存区域). 另外linux c多线程编程,在使用内存集时,您需要包含string.h头文件
参考资料:
1. Linux下的多线程编程
2. pthread_delay_np(这是posix条件变量的示例)
3. pthread_join和segfault(非常感谢你们,请注意)
4. posix线程编程指南[学习linux下的多线程,如果您不读此书,将会后悔]
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-286384-1.html