Ubuntu中线程创建及线程同步互斥

线程

  • 一. 线程是什么
  • 二.在Ubuntu中创建线程
      • 1.线程的创建
      • 2.线程等待
      • 3.线程退出
      • 4.线程取消
      • 5.线程分离
  • 三.线程的资源互斥
  • 四、线程资源的同步
          • 同步与互斥的关系

一. 线程是什么

线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

二.在Ubuntu中创建线程

1.线程的创建

#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. 创建线程后,主线程和子线程访问的是同一空间的数据

2.线程等待

线程等待:在主线程中调用,等待子线程的退出,并接收子线程的返回结果。

#include 
int pthread_join(pthread_t thread, void **retval);
//Compile and link with -pthread.
参数
	参数1:thread表示等待的子线程的线程id;
	参数2:retval用来接收返回结果,
返回值:
	成功返回0
	失败返回错误号;

3.线程退出

#include 
void pthread_exit(void *retval);
//Compile and link with -pthread.
参数:retval线程的退出的结果。该线程退出,对其他线程没有影响。

4.线程取消

线程的取消:由主线程给子线程发送取消请求,子线程结束;

#include 
int pthread_cancel(pthread_t thread);
//Compile and link with -pthread.
参数:
	pthread表示所有取消线程的线程id;
返回值:
	成功返回0
	失败返回错误号

5.线程分离

线程分离:在主线程中去分离子线程,分离的子线程退出的时候,子线程会对自己的资源做回收处理

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;
}

三.线程的资源互斥

在多个线程访问临界资源(共享资源),可能同时被多个任务进行读写,出现资源的互斥,互斥的结果会导致数据不完整;
解决资源的互斥:在同一个时间,资源只能被某一个任务进行访问。可以是互斥锁来实现:
具体实现流程:

  1. 初始化互斥锁:
int  pthread_mutex_init(pthread_mutex_t  *mutex,  const  pthread_mutex_attr_t *mutexattr);
参数:
	参数1:mutex表示的是互斥锁的标号;
	参数2:mutexattr表示的互斥锁的属性,一般情况使用NULL,表示缺省属性。
返回值:
	成功返回0
	失败返回错误号	
  1. 在访问临界资源前,需要上锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
参数: mutex表示的是互斥锁的标号;
  1. 在访问临界资源结束,需要解锁
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);
}

四、线程资源的同步

线程的同步:
在多个任务执行的时候,任务需要按照某种特定的顺序执行,任务与任务之间由明确的先后执行顺序。
同步的实现,可以采用信号量来实现:

  1. 信号量初始化
#include 
int sem_init(sem_t *sem, int pshared, unsigned int value);
//Link with -lrt or -pthread.
参数:
		参数1: sem表示的是信号量的标号;
		参数2: pshared表示信号量的作用范围;
		参数3:value表示信号量的初始值(资源);
  1. P操作
    int sem_wait(sem_t *sem); // P操作
  2. V操作
    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进程就不能运行它们之中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行。

同步:是指散步在不同进程之间的若干程序片断,它们的运行必须严格按照规定的 某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。  

联系:

同步是一种更为复杂的互斥,而互斥是一种特殊的同步。也就是说互斥是两个线程之间不可以同时运行,他们会相互排斥,必须等待一个线程运行完毕,另一个才能运行,而同步也是不能同时运行,但他是必须要安照某种次序来运行相应的线程(也是一种互斥)。

互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。  

同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。

你可能感兴趣的:(进程线程,Linux,多线程,c++)