线程包含于进程中,是进程的实际运作单位。一个进程中可包含有多个线程,所有线程共用同一块资源,同样的一个线程的错误会导致整个进程出现问题。使用线程是因为线程的开销远小于进程,同时进程之间数据的通信相对复杂,而线程共用相同空间,会方便很多。
多线程目前在Linux平台上有成熟的pthread库,其主要开发分为三块,线程,互斥锁和条件。
1.线程操作:创建,退出,等待。
API:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
pthread_create:第一个参数为线程的ID,第二个参数是线程的属性(可设置为NULL,默认),第三个参数是线程具体做什么的函数指针,第四个参数是线程需要传的参数(多个参数需要传入用结构体)。
int pthread_exit(void *rval_ptr);
pthread_exit:参数为要返回的数据,要求是static。不然结束之后栈就没了。
int pthread_join(pthread_t thread, void **rval_ptr);
pthread_join:第一个参数为等待哪一个线程,第二个参数是pthread_exit返回的数据存入哪里。
#include <pthread.h> #include <stdio.h> void *func1(void *arg) { static char *ret = "it is a test!"; printf("t1: %ld , thread is created\n", (unsigned long)pthread_self()); printf("t1:parame get %d\n",*((int *)arg)); pthread_exit((void *)ret); } int main() { pthread_t t1; int parame = 55; int ret; char *pstr = NULL; ret = pthread_create(&t1, NULL, func1, (void *)¶me); if(ret == 0){ printf("main :thread create success\n"); } printf("main : thred %ld\n", (unsigned long)pthread_self()); pthread_join(t1, (void **)&pstr); printf("func1 return is : %s\n", pstr); return 0; }
2.互斥锁:创建,加锁,解锁,销毁
互斥量(mutex)就是一把锁,在访问资源前对互斥量加锁,访问结束后解锁。互斥量在使用时需要进行初始化,也可以静态分配为(PTHREAD_MUTEX_INITIALIZER)。
API:
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
pthread_mutex_init:第一个参数为要操作哪一个互斥量,第二个参数为属性,写NULL默认。
int pthread_mutex_lock(pthread_mutex_t *mutex);
pthread_mutex_lock:参数为互斥量地址。
int pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_unlock:参数为互斥量地址。
int pthread_mutex_destroy(pthread_mutex_t mutex);
pthread_mutex_destroy:参数为互斥量地址。
#include <pthread.h> #include <stdio.h> int data = 0; pthread_mutex_t mutex1; void *func1(void *arg) { pthread_mutex_lock(&mutex1); printf("t1: %ld , thread is created\n", (unsigned long)pthread_self()); printf("t1:parame get %d\n",*((int *)arg)); while(1){ printf("t1 : %d\n", data++); sleep(1); if(data == 3){ printf("3 qiut ///\n"); pthread_mutex_unlock(&mutex1); pthread_exit(NULL); } } } void *func2(void *arg) { printf("t2: %ld , thread is created\n", (unsigned long)pthread_self()); printf("t2:parame get %d\n",*((int *)arg)); while(1){ printf("t2: %d\n", data); pthread_mutex_lock(&mutex1); data++; pthread_mutex_unlock(&mutex1); sleep(1); } } int main() { pthread_t t1; pthread_t t2; int parame = 55; int ret; char *pstr = NULL; pthread_mutex_init(&mutex1, NULL); ret = pthread_create(&t1, NULL, func1, (void *)¶me); if(ret == 0){ printf("main :thread1 create success\n"); } ret = pthread_create(&t2, NULL, func2, (void *)¶me); if(ret == 0){ printf("main :thread2 create success\n"); } printf("main : thred %ld\n", (unsigned long)pthread_self()); while(1){ printf("main : %d\n", data); sleep(1); } pthread_join(t1, (void **)&pstr); pthread_join(t2, (void **)&pstr); pthread_mutex_destroy(&mutex1); return 0; }
这个例子定义了一个全局变量data作为共享资源,要实现直到data加到3,线程1才退出。即使一开始是线程2先运行,进入循环,也最多加一次。因为sleep后线程1竞争成功会立即对互斥量加锁,直到data = 3的时候线程解锁并退出。
3.条件操作:创建,销毁,触发,广播,等待
API:
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
pthread_cond_init:第一个参数操作哪一个条件,第二个参数是属性。
int pthread_cond_destroy(pthread_cond_t *cond);
pthread_cond_destroy:参数为条件的地址
int pthread_cond_signal(pthread_cond_t *cond);
pthread_cond_signal:触发哪一个条件。
int pthread_cond_broadcast(pthread_cond_t cond);
pthread_cond_broadcast:触发所有等待这个条件的线程。
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
pthread_cond_wait:第一个参数是条件的地址,第二个参数是互斥锁的地址。
#include <stdio.h> #include <pthread.h> #include <stdlib.h> int data = 0; pthread_mutex_t mutex1; pthread_cond_t cond1; void *func1(void *arg) { static int cnt = 0; while(1){ pthread_cond_wait(&cond1, &mutex1); printf("t1 run ///\n"); printf("t1 data is :%d\n", data); data = 0; sleep(1); if(cnt ++ == 10){ printf("return 10\n"); exit(1); } } } void *func2(void *arg) { while(1){ printf("t2 data is :%d\n", data); pthread_mutex_lock(&mutex1); data++; if(data == 3){ pthread_cond_signal(&cond1); } pthread_mutex_unlock(&mutex1); sleep(1); } } // int main() { pthread_t t1; pthread_t t2; int parame = 10; int ret; pthread_mutex_init(&mutex1, NULL); pthread_cond_init(&cond1, NULL); ret = pthread_create(&t1, NULL, func1, ¶me); if(ret == 0){ // printf("main: thread t1 create success\n"); } ret = pthread_create(&t2, NULL, func2, ¶me); if(ret == 0){ // printf("main: thread t2 create success\n"); } pthread_join(t1, NULL); pthread_join(t2, NULL); pthread_mutex_destroy(&mutex1); pthread_cond_destroy(&cond1); return 0; }
线程的基本操作大致就这些,可以去看一下线程生产者和消费者的相关例子进行学习。
同时也可以看一下这篇文章:
Linux多线程编程初探