线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
#include
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
//Compile and link with -pthread. /* 在程序编译时,需要链接线程库 pthread */
参数:
参数1:thread表示,在线程创建成功的时候,用来接收线程的线程id;
参数2:attr表示的是所创建线程的属性,一般情况使用NULL,表示缺省属性。
参数3:start_routine是一个(参数是void*,返回值是void*)函数指针,子线程的执行函数(需要由用户自定义)的地址;
参数4: arg给参数3做为参数。
返回值:
成功返回0
失败返回错误号;
PS:
1. 创建线程成功,子线程和主线程的执行顺序是随机执行;
2. 在创建线程成功后,
如果子线程中没有使用exit,子线程退出,不会影响其他线程。
如果主线程不是因为pthread_exit退出,主线程退出,子线程会结束。
3. 创建线程后,主线程和子线程访问的是同一空间的数据
线程等待:在主线程中调用,等待子线程的退出,并接收子线程的返回结果。
#include
int pthread_join(pthread_t thread, void **retval);
//Compile and link with -pthread.
参数
参数1:thread表示等待的子线程的线程id;
参数2:retval用来接收返回结果,
返回值:
成功返回0
失败返回错误号;
#include
void pthread_exit(void *retval);
//Compile and link with -pthread.
参数:retval线程的退出的结果。该线程退出,对其他线程没有影响。
线程的取消:由主线程给子线程发送取消请求,子线程结束;
#include
int pthread_cancel(pthread_t thread);
//Compile and link with -pthread.
参数:
pthread表示所有取消线程的线程id;
返回值:
成功返回0
失败返回错误号
线程分离:在主线程中去分离子线程,分离的子线程退出的时候,子线程会对自己的资源做回收处理
int pthread_detach(pthread_t thread);
参数: thread表示分离的子线程的线程id;
返回值:
成功返回0
失败返回错误号
创建线程代码示例:
#include
#include
#include
#include
#include
#include
void *mythread(void *arg) //子线程处理函数
{
int num = (int)arg;
printf("child thread : %d \n",2*num);
return (void*)0;
}
int main(int argc, char *argv[])
{
pthread_t pid;
int num;
printf("please input num:");
scanf("%d",&num);
int res = pthread_create(&pid,NULL,mythread,(void *)num); //创建线程,带参数
if(res != 0)
{
perror("pthread_create");
}
pthread_join(pid,NULL);//等待子线程退出
printf("main thread:%d\n",num);
return 0;
}
在多个线程访问临界资源(共享资源),可能同时被多个任务进行读写,出现资源的互斥,互斥的结果会导致数据不完整;
解决资源的互斥:在同一个时间,资源只能被某一个任务进行访问。可以是互斥锁来实现:
具体实现流程:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);
参数:
参数1:mutex表示的是互斥锁的标号;
参数2:mutexattr表示的互斥锁的属性,一般情况使用NULL,表示缺省属性。
返回值:
成功返回0
失败返回错误号
int pthread_mutex_lock(pthread_mutex_t *mutex);
参数: mutex表示的是互斥锁的标号;
int pthread_mutex_unlock(pthread_mutex_t *mutex);
参数: mutex表示的是互斥锁的标号;
线程互斥代码示例:
#include
#include
#include
#include
#include
int a = 0;
pthread_mutex_t mutex;
void *thread_func(void *arg)
{
int i;
for (i = 0; i < 100000; i++) {
/* 上锁,其他任务不能访问该临界资源 */
pthread_mutex_lock(&mutex);
a++; /* 原子操作,不能被打断 */
/* 解锁:其他任务就可以访问临界资源 */
pthread_mutex_unlock(&mutex);
}
}
int main()
{
int ret;
pthread_t thread_id1;
pthread_t thread_id2;
pthread_t thread_id3;
pthread_t thread_id4;
/* 初始化线程的互斥锁 */
ret = pthread_mutex_init(&mutex, NULL);
if (ret != 0) {
fprintf(stderr, "pthread_mutex_init fail\n");
return -1;
}
/* 创建一个子线程 */
ret = pthread_create(&thread_id1, NULL, thread_func, NULL);
if (ret != 0) {
fprintf(stderr, "create thread fail\n");
return -1;
}
ret = pthread_create(&thread_id2, NULL, thread_func, NULL);
if (ret != 0) {
fprintf(stderr, "create thread fail\n");
return -1;
}
ret = pthread_create(&thread_id3, NULL, thread_func, NULL);
if (ret != 0) {
fprintf(stderr, "create thread fail\n");
return -1;
}
ret = pthread_create(&thread_id4, NULL, thread_func, NULL);
if (ret != 0) {
fprintf(stderr, "create thread fail\n");
return -1;
}
pthread_join(thread_id1, NULL);
pthread_join(thread_id2, NULL);
pthread_join(thread_id3, NULL);
pthread_join(thread_id4, NULL);
printf("main thread : a = %d\n", a);
pthread_exit(NULL);
}
线程的同步:
在多个任务执行的时候,任务需要按照某种特定的顺序执行,任务与任务之间由明确的先后执行顺序。
同步的实现,可以采用信号量来实现:
#include
int sem_init(sem_t *sem, int pshared, unsigned int value);
//Link with -lrt or -pthread.
参数:
参数1: sem表示的是信号量的标号;
参数2: pshared表示信号量的作用范围;
参数3:value表示信号量的初始值(资源);
int sem_wait(sem_t *sem);
// P操作int sem_post(sem_t *sem);
// V操作线程同步代码示例:
#include
#include
#include
#include
#include
#include
char buf[256];
int a = 5;
sem_t sem;
void *thread_show(void *arg)
{
while(1) {
fgets(buf, sizeof(buf), stdin);
a++;
sem_post(&sem);
}
}
void *thread_test(void *arg)
{
while(1) {
sem_wait(&sem);
a--;
printf("%d, %s\n", a, buf);
}
}
int main()
{
int ret;
pthread_t thread_id;
/* 初始化信号量 */
ret = sem_init(&sem, 0, 5);
if (ret == -1) {
perror("sem_init");
return -1;
}
/* 创建一个子线程 */
ret = pthread_create(&thread_id, NULL, thread_show, NULL);
if (ret != 0) {
fprintf(stderr, "create thread fail\n");
return -1;
}
ret = pthread_create(&thread_id, NULL, thread_test, NULL);
if (ret != 0) {
fprintf(stderr, "create thread fail\n");
return -1;
}
while(1);
}
区别:
互斥:是bai指三部在du不同进程之间的若干程序zhi片断,当某dao个进程运行其中一个zhuan程序片段时,其它shu进程就不能运行它们之中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行。
同步:是指散步在不同进程之间的若干程序片断,它们的运行必须严格按照规定的 某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。
联系:
同步是一种更为复杂的互斥,而互斥是一种特殊的同步。也就是说互斥是两个线程之间不可以同时运行,他们会相互排斥,必须等待一个线程运行完毕,另一个才能运行,而同步也是不能同时运行,但他是必须要安照某种次序来运行相应的线程(也是一种互斥)。
互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。