As you see, if sharedData from C side is not declared as volatile, then is there still a guarantee that Thread 2 can always get the latest value set by Thread 1?
No, and marking it volatile has no effect on threading either way.
Does the same apply to Java using JNI too?
Yes, and it also applies to PHP, Lua, Python, and any other language that can pull in a C library in that way.
To elaborate on your first question, the volatile keyword in C is not used for threading, it is used to tell the compiler not to optimize on that variable.
Take for example the following code:
#include <stdio.h>
#include <stdbool.h>
#include <limits.h>
static bool run; // = false
void do_run(void)
{
unsigned long v = 1;
while (run) {
if (++v == ULONG_MAX) run = false;
}
printf("v = %lu\n", v);
}
void set_run(bool value)
{
run = value;
}
int main(int argc, char** argv)
{
set_run(true);
do_run();
return 0;
}
With optimizations turned on, the compiler might see a lot of areas to remove unnecessary code without side effect, and do so; for instance, the compiler could see that unsigned long v will always be ULONG_MAX in the do_run function and opt instead to simply return ULONG_MAX.
And in fact when I run gcc -O3 on the above code, that's exactly what happens, with the do_run function returning immediately and printing v = 18446744073709551615.
If you were to mark run as volatile, then the compiler can't optimize that variable, which usually means it cannot optimize the areas of code with that variable in certain ways.
To wit, when I change run to static volatile bool run; and then compile using gcc -O3, my program now stalls waiting for the loop to iterate through 18446744073709551615 times.
That aside, when you make a call into an external library, the only thread-safety you have is that provided by the language utilized in that library.
For C, you must explicitly specify thread safety in functions. So for your code, even though you are utilizing the lock context in the managed code, it is only locking for the managed code and the C code itself is still not thread safe.
Take for example the following code:
C code
static volatile int sharedData;
static volatile bool doRun;
static pthread_t addThread;
void* runThread(void* data)
{
while (doRun) {
++sharedData;
}
return NULL;
}
void startThread(void)
{
doRun = true;
pthread_create(&addThread, NULL, &runThread, NULL);
}
void stopThread(void)
{
doRun = false;
}
void setData(int data)
{
sharedData = data;
}
int getData(void)
{
return sharedData;
}
C# code
// Thread 1
startThread();
while (true) {
lock (key) {
setData(++i);
}
}
// Thread 2
while (true) {
lock (key) {
i = getData();
}
}
stopThread();
In this code, when lock (key) is called, the only guarantee you have is that i will be protected in the C# code. However, since the C code is also running a thread (because thread 1 called startThread), then you do not have any guarantee that the C# code will be properly synchronized.
To make the C code thread-safe, you will have to specifically add a mutex or semaphore to suit your needs:
static int sharedData;
static volatile bool doRun;
static pthread_t addThread;
static pthread_mutex_t key;
void* runThread(void* data)
{
while (doRun) {
pthread_mutex_lock(&key);
++sharedData;
pthread_mutex_unlock(&key);
}
return NULL;
}
void startThread(void)
{
doRun = true;
pthread_mutex_init(&key, NULL);
pthread_create(&addThread, NULL, &runThread, NULL);
}
void stopThread(void)
{
doRun = false;
pthread_mutex_lock(&key);
pthread_mutex_unlock(&key);
pthread_mutex_destroy(&key);
}
void setData(int data)
{
pthread_mutex_lock(&key);
sharedData = data;
pthread_mutex_unlock(&key);
}
int getData(void)
{
int ret = 0;
pthread_mutex_lock(&key);
ret = sharedData;
pthread_mutex_unlock(&key);
return ret;
}
In this way, the underlying library calls are protected appropriately and any number of processes sharing the memory of this library will also then be thread-safe.
I should note that the above utilizes POSIX for thread synchronization, but the WinAPI, or the C11 standard mutex could also be utilized depending on your target system.
I hope that can help.