Thread Control 2

3. The private data (a multi-value key technology)

Multi-threaded environment, the data space shared by all threads in the process of the process, and therefore the global variables for all threads public. Sometimes, you need to save their own thread global variable, the global variable is only valid within a thread, each function can access private global variables that thread, this is a key multi-value technology, that is a key corresponds to multiple values.

When accessing the data are accessed by keys, access appears to be a variable, the actual access different data.

#include <pthread.h> 
int pthread_key_create (pthread_key_t * Key, void (* dest_function) (void *)); // create a key 
int pthread_setspecific (pthread_key_t key, const void * pointer); // Set the thread is a key private data 
void * pthread_getspecific (pthread_key_t key); // read data from a key thread private 
int pthread_key_delete (pthread_key_t key); // delete a key

 pthread_key_create: Linux distribution from a pool of TSD, assign it to provide access to use the key, the first key parameter to point to a key-pointer, the second parameter is a function pointer, if the pointer is not empty, when a thread exits will 2key associated data calls destr_function as parameters, release the allocated buffer.

Once the key value is created, all threads have access to him, each thread can be provided according to their needs to fill in a key value, equivalent to a global variable with the same name but different values, a key multi-valued.

pthread_setspecific: This function pointer when the value of key values ​​associated with pthread_setspecific is a key function to specify a new thread, the thread must release the original thread data to reclaim space.

pthread_getspecific: obtain data associated with key by the function.

pthread_key_delete: This function is used to delete a key, delete key occupied by the memory will be released. Note that when the key is released the memory occupied, and the thread associated with the key data memory occupied and will not be released. Thus, the release thread data must be completed before releasing the key.

Routine

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h>

pthread_key_t key;


void func()
{
	printf("key's value is %d\n", pthread_getspecific(key));
}
void *thread2(void *arg)
{
	int tsd = 5;
	printf("thread %ld is running\n", pthread_self());
	pthread_setspecific(key, (void*)tsd);
	printf("thread2 %ld return %d\n", pthread_self(), pthread_getspecific(key));
	func();
}


void *thread1(void *arg)
{
	int tsd = 0;
	pthread_t thid2;
	printf("thread %ld is running\n", pthread_self());
	pthread_create(&thid2, NULL, thread2, NULL);
	sleep(2);
	printf("thread1 %ld returns %d\n",pthread_self(), pthread_getspecific(key));
	func();
}
int main()
{
	pthread_t thid;
	printf("main thread begins running\n");
	pthread_key_create(&key, NULL);
	pthread_create(&thid, NULL, thread1, NULL);
	sleep(3);
	pthread_key_delete(key);
	printf("main thread exit\n");
	return 0;
}

 operation result

 

 You can see, each thread is returned when you call the function func is still the key to set the value of its own thread.

4. Thread Synchronization

4.1 mutex

Multithreading to achieve synchronization between threads by providing the key code lock manner.

Mutex function

#include<pthread.h>
pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);//初始化一个互斥锁
pthread_mutex_destory(pthread_mutex_t *mutex);//注销一个互斥锁
pthread_mutex_unlock(pthread_mutex_t *mutex);//加锁,若不成功,阻塞等待
pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁
pthread_mutex_trylock(pthread_mutex_t *mutex);//测试加锁,若不成功立即返回,错误码为EBUSY

 使用互斥锁之前必须先进行初始化操作。初始化的方式有两种,一种是静态赋值法,将宏常量PTHREAD_MUTEX_INITIALIZER赋值给互斥锁

pthread_mutex_t mutex = PTHREAD_MUTEX_INITILIZER;

 另外一种方式就是通过pthread_mutex_init函数初始化互斥,函数原型如上

参数mutexattr表示互斥锁的属性,如果为NULL则使用默认属性。

初始化结束后就可以使用pthread_mutex_lock,pthread_mutex_trylock这两个函数给互斥锁加锁了。

用pthread_mutex_lock()加锁时,如果mutex已经被锁住,当前尝试加锁的线程就会阻塞,直至互斥锁被其他线程释放。当pthread_mutex_lock函数返回时,说明互斥锁已经被当前线程加锁成功。pthread_mutex_lock则不同,若mutex已经被加锁,他将立即返回,返回的错误码为EBUSY,而不是阻塞等待。

注:加锁时,无论何种类型的锁,都不可能同时被两个不同的线程同时获得,其中一个必须等待解锁。在同一进程中的线程,若加锁后没有解锁,其他线程将无法再获得该锁。

锁用完后应当解锁,使用pthread_mutex_unlock函数解锁时,要满足两个条件:一个是互斥锁必须处于加锁状态,二是调用本函数的线程必须是给互斥锁加锁的线程(即加锁前锁还在,谁加锁谁解锁)。

互斥锁使用完毕后,必须进行清除。清除互斥锁使用函数pthread_mutex_destory,函数原型如上。

清除一个互斥锁将会释放它所占用的资源。清除互斥锁时要求锁处于放开的状态。若锁处于锁定状态,函数返回EBUSY,该函数成功执行时返回0。由于在Linux中,互斥锁并不占用内存,因此pthread_mutex_destory()除了解除互斥锁的状态外再无任何作用。

例程(文件读写保护)

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>

#define File  "output.txt"

pthread_mutex_t number_mutex;

void *pthread1(void *arg)
{
	int t = 5;
	while(t)
	{
		write_max(File);
		sleep(1);
	 	--t;
	}
}

void *pthread2(void *arg)
{
	int t = 5;
	while(t)
	{
		read_max(File);
		sleep(1);
		--t;
	}
}
void write_max(char *file)
{
	unsigned long long a = 0;
	int b = 0;
	char timeStr[14], ch;
	time_t timer;
	struct tm *tblock;
	time(&timer);
	tblock = gmtime(&timer);
	a = (tblock->tm_year+1900)*100;
	a = (a+tblock->tm_mon+1)*100;
	a = (a+tblock->tm_mday)*100;
	a = (a+tblock->tm_hour+8)*100;
	a = (a+tblock->tm_min)*100;
	a = (a+tblock->tm_sec);
	sprintf(timeStr, "%llu", a);
	pthread_mutex_lock(&number_mutex);
	FILE *fp;
	fp = fopen(file, "w");
	if(fp == NULL)
	{
		printf("Open file failed\n");
		fclose(fp);
		exit(1);
	}
	while(timeStr[b] != '\0')
	{
		fputc(timeStr[b], fp);
		++b;
	}
	printf("pthread = %ld writing %s to %s\n", pthread_self(), timeStr, file);
	fclose(fp);
	pthread_mutex_unlock(&number_mutex);
}
void read_max(char *file)
{
	char ch[14], *rc = NULL;
	pthread_mutex_lock(&number_mutex);
	FILE *fp;
	fp = fopen(file, "r");
	if(fp == NULL)
	{
		printf("Open file error\n");
		fclose(fp);
		exit(1);
	}
	rc = fgets(ch, 15, fp);
	printf("pthread = %ld, time = %s\n", pthread_self(), ch);
	fclose(fp);
	pthread_mutex_unlock(&number_mutex);
}


int main()
{
	pthread_t th1, th2;
	pthread_create(&th1, NULL, pthread1, NULL);
	pthread_create(&th2, NULL, pthread2, NULL);
	sleep(6);
	return 0;
}

 运行结果

 

 当程序中多个线程都要对一个文件进行读写操作的时候,为保证同步和文件安全,在一个线程对文件进行操作时必须加锁,其余要使用文件的线程先等待锁被释放后随机获得互斥锁。

(将写和读程序的加锁解锁代码都注释以后)

 

 同时对文件操作导致未知的数据出现在文件中。



Guess you like

Origin www.cnblogs.com/area-h-p/p/11599652.html