How to use global variable in a multithreaded program?
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
How to use global variable in a multithreaded program?
My project is based on the program VLC media player, a multithreaded program. I wish to use a global variable as a counter in this program across various files and folders. How should I do this?
but i cannot get it done in VLC media player. For example, in the VLC /modules/control/hotkeys.c, I don't know where the vlc_keys.h header file locates (which is 1 of the files i wish to include the global variable).
I had thought of writing another header file for the global variable, but i don't know how to include it in the makefile. So does anyone has idea on it?
I'm guessing here that you will encounter a major problem which has nothing to do with the question you ask. But I'll leave that major problem until the end of this post. I'll answer your actual question first.
My personal preference would be to avoid changing the makefile. Others may say differently, but they are made from sterner stuff than I am. :)
Find a header file (a .h file) in the project that's already included (directly or indirectly) by all the source files containing actual code (.c files) which you'll want to change to look at this variable. As shown in the URL you cite, declare the variable in the header file, and define the variable in the source code file.
That page does have one thing backwards, which might be confusing. It says:
Quote:
*** Note: The declaration source file should include (#include) the definition header file.
It really means:
Quote:
*** Note: The definition source file should include (#include) the declaration header file.
In other words, the .c file which defines the variable should include the .h file which declares the variable.
Then you can freely access that variable in not only the .c file which defines the variable, but also any other .c file which includes the .h file and is linked into the same executable as the .c file which defines the variable.
When you're done, it wouldn't hurt to force a complete recompilation. Most projects are defined so that you can do that thus:
Code:
make clean
make
or
Code:
make clean
make install
Now, as promised:
->->-> HERE IS YOUR MAJOR PROBLEM. <-<-<-
If this variable is to be accessed across threads, make sure you're protecting it with a mutex and a condition variable. These should also be global, just as the counter variable is.
Do not do any of this unless you are very familiar with pthreads programming. My guess is that if you're asking a question about header files and global variables, you're probably not familiar with pthreads programming.
pthreads programming is not rocket science, but it's far from trivial. The concepts are straightforward, but it's easy to miss some of the implications of those concepts and then find yourself immersed in seemingly infinite hours and hours of enjoyable debugging of a program which only misbehaves one percent of the time.
If my guess is right and you're not very familiar with pthreads programming, then run (do not walk) to your nearest bookseller and order a copy of Programming with POSIX Threads by David R. Butenhof. It's published by Addison Wesley.
My copy of the O'Reilly book on the same subject seems to have all the parts there, but it doesn't go out of its way to educate you on some aspects of the design philosophy of pthreads, and some of the implications of doing things wrong. That can cost you much open-ended debugging time. That, in my opinion, makes the O'Reilly book dangerous. Get the Addison Wesley one.
When you're familiar with pthreads programming, and you figure out how to introduce this counter variable without introducing deadlock (heh heh), you're all set!
Find a header file (a .h file) in the project that's already included (directly or indirectly) by all the source files containing actual code (.c files) which you'll want to change to look at this variable.
but i really cannot find out the vlc_keys.h header file in the /modules/control folder as used by hotkeys.c file in the VLC source tarball i downloaded from http://download.videolan.org/pub/vlc...-0.8.6f.tar.gz
Where would this header file locates?
Quote:
If this variable is to be accessed across threads, make sure you're protecting it with a mutex and a condition variable. These should also be global, just as the counter variable is.
that means i have to take care of those threads which will be using this counter variable to avoid the problem deadlock as you mentioned? How about other threads that do not use the counter variable? They won't be affected right?
Unfortunately, I don't have the time to dig into that particular project. There are two ways you can approach this.
Find the .c files in the project where you'll be interested in the counter.
Find any .h file within the project which is included by all of these .c files, and modify that one.
The other approach, if the number of .c files involved with this counter is small, say two or three at the most, just take the line that you would have added to some .h file, and add it (identical in content) to each of these .c files. There's nothing that requires that the declaration be in a .h file; it's just that if you declare the variable in only one place, it's easier to maintain your code in the long run. But if you need to put the declaration in each of the .c files, just do it. But if I were you, I'd place a comment next to the declaration in each file listing all the .c files where this declaration exists, so if you change it in one place, you'll be able to find all the other places so you can change them too.
And the reason for protecting this variable with a mutex and a condition variable is not to protect against deadlock, but rather to provide data integrity. Deadlock will arise if you claim mutexes in the wrong order, so each of two threads is waiting on the other forever, or perhaps a similar but more complex situation.
Your question of the purpose of a mutex and a condition variable is a good one, but it illustrates the point that you really need to read almost from cover to cover the book I recommended, or there's a good chance you will quickly descend into troubles which are far beyond the scope of this or any other forum to help you out of.
The other approach, if the number of .c files involved with this counter is small, say two or three at the most, just take the line that you would have added to some .h file, and add it (identical in content) to each of these .c files. There's nothing that requires that the declaration be in a .h file; it's just that if you declare the variable in only one place, it's easier to maintain your code in the long run. But if you need to put the declaration in each of the .c files, just do it. But if I were you, I'd place a comment next to the declaration in each file listing all the .c files where this declaration exists, so if you change it in one place, you'll be able to find all the other places so you can change them too.
Do you mean i do not need to declare the variable in the header file, but declare it in every .c files that it? What if the .c file is in another directory? How should i declare it in the file?
To find 'vlc_keys.h', goto the root-directory of your project (or where the vlc source files are installed); then run this command:
Code:
find . -name vlc_keys.h
If you want to add a simple variable (an unsigned int for instance) to use as a counter, define it within an existing header file, or create your own header file. A good Makefile will not need to have a list of header files in it since header files that are needed by the project can be deduced by examining the .c files in the project (btw, this is known as building dependencies).
Anyhow, after you have defined your counter, go edit one or more .c files to increment (or decrement) your counter as needed, and also wherever necessary, display it.
For a simple data type such as an unsigned int, I don't think it is necessary to worry about protecting the write/read operations to it with a mutex since those operations will occur atomically using one CPU instruction.
For more complex data, where two or more steps are necessary to "massage" the data, then without a doubt, a mutex or semaphore would be needed to guard against concurrent access to the data.
You need to be aware of the shape of the project you're building (or rebuilding). Keep in mind that global variables are used among various functions of the sameprogram. It doesn't matter whether the .c files containing these functions are in the same directory or not. It only matters that the functions are linked together into the same executable program.
It still matters, though, that you be concerned about data integrity. dwhitney67 says:
Quote:
For a simple data type such as an unsigned int, I don't think it is necessary to worry about protecting the write/read operations to it with a mutex since those operations will occur atomically using one CPU instruction.
No, not so much. Consider the following simple source:
Code:
unsigned int a;
int main(void)
{
a++;
return 0;
} /* main() */
It takes those three instructions in red to increment a. If you have more than one thread which might be incrementing that count, you can have problems. Usually it will work, and one time out of, oh, a half zillion it won't.
If you're not worried about bulletproof, mission-critical accuracy, you can let it go and not worry about mutexes and condition variables. But once in a while your count will be off. Is this ok with you? If so, don't worry; be happy.
If you're not worried about bulletproof, mission-critical accuracy, you can let it go and not worry about mutexes and condition variables. But once in a while your count will be off. Is this ok with you? If so, don't worry; be happy.
That is pretty much it. If you don't use mutexes, then you will always have a race condition regarding access to that variable. It could be that it doesn't matter; if the variable is changed while being accessed, then a thread might loop one more time through a loop than it needs to, and this extra loop might cost nothing but a few CPU cycles. In this case, it really doesn't matter that much - and it is indeed a bit of extra work (only a bit) to employ a mutex.
I would normally consider it to be proper practice to always use a mutex, though, even in the case where it really doesn't matter. Why? Because it might not matter now, but after you make further modifications/upgrades to the program, suddenly that race condition becomes critical. If you employed the mutex from the beginning, you don't have to worry about it or even think about it. If you didn't use the mutex, then the change that makes it critical has introduced a bug that you'll have one hell of a time figuring out - unless, that is, you happen to remember or notice that you are accessing a variable without using a mutex.
Do it right the first time, then you can forget about it forever. Use the mutex, and you'll never find yourself surprised by that kind of bug.
I agree that you shouldn't even start programming until you've done some serious threading reading. If you don't understand what's going on (and why as above re mutex), you'll get a prog that
1. won't work
and
2. you can't debug
As above, its not rocket science, but it does require very careful attention to detail and a clear understanding of the principles.
Take it from someone who taught himself from the online perl docs ... not the easiest thing I've ever done
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.